Initial revision

This commit is contained in:
Ben Gras 2005-04-21 14:53:53 +00:00
commit 9865aeaa79
2264 changed files with 411685 additions and 0 deletions

32
LICENSE Executable file
View file

@ -0,0 +1,32 @@
Copyright (c) 1987,1997,2001 Prentice Hall
All rights reserved.
Redistribution and use of the MINIX operating system in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Prentice Hall nor the names of the software
authors or contributors may be used to endorse or promote
products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

51
Makefile Executable file
View file

@ -0,0 +1,51 @@
# Master Makefile to compile everything in /usr/src except the system.
MAKE = exec make -$(MAKEFLAGS)
usage:
@echo "" >&2
@echo "Master Makefile for MINIX commands and utilities." >&2
@echo "Usage:" >&2
@echo " make world # Compile everything (libraries & commands)" >&2
@echo " make libraries # Compile and install libraries" >&2
@echo " make commands # Compile commands, but don't install" >&2
@echo " make install # Compile and install commands" >&2
@echo " make clean # Remove all compiler results" >&2
@echo "" >&2
@echo "Run 'make' in tools/ to create a new MINIX configuration." >&2; exit 0
@echo "" >&2
# world has to be able to make a new system, even if there
# is no complete old system. it has to install commands, for which
# it has to install libraries, for which it has to install includes,
# for which it has to install /etc (for users and ownerships).
# etcfiles also creates a directory hierarchy in its
# 'make install' target.
world: etcfiles includes libraries commands install
libraries:
cd lib && $(MAKE) install
commands:
@echo "Are the libraries up to date?"; sleep 2
test ! -f commands/Makefile || { cd commands && $(MAKE); }
install:
test ! -f commands/Makefile || { cd commands && $(MAKE) $@; }
clean::
cd lib && $(MAKE) $@
test ! -f commands/Makefile || { cd commands && $(MAKE) $@; }
etcfiles::
cd etc && $(MAKE) install
includes::
cd include && $(MAKE) install
all install clean::
cd boot && $(MAKE) $@
test ! -f commands/Makefile || { cd commands && $(MAKE) $@; }
cd tools && $(MAKE) $@
cd man && $(MAKE) $@

116
boot/Makefile Executable file
View file

@ -0,0 +1,116 @@
# Makefile for the boot monitor package.
SYS = ..
CC = exec cc
CC86 = exec cc -mi86 -Was-ncc
CFLAGS = -I$(SYS)
LIBS = -lsys
LD = $(CC) -s -.o
LD86 = $(CC86) -.o
BIN = /usr/bin
MDEC = /usr/mdec
all: bootblock boot edparams masterboot jumpboot installboot addaout
dos: boot.com mkfile.com
bootblock: bootblock.s
$(LD86) -com -o $@ bootblock.s
masterboot: masterboot.s
$(LD86) -com -o $@ masterboot.s
jumpboot: jumpboot.s
$(LD86) -com -o $@ jumpboot.s
boot.o: boot.c
$(CC86) $(CFLAGS) -c boot.c
bootimage.o: bootimage.c
$(CC86) $(CFLAGS) -c bootimage.c
rawfs86.o: rawfs.c rawfs.o
ln -f rawfs.c rawfs86.c
$(CC86) $(CFLAGS) -c rawfs86.c
rm rawfs86.c
-cmp -s rawfs.o rawfs86.o && ln -f rawfs.o rawfs86.o
boot: boothead.s boot.o bootimage.o rawfs86.o
$(LD86) -o $@ \
boothead.s boot.o bootimage.o rawfs86.o $(LIBS)
install -S 16kb boot
edparams.o: boot.c
ln -f boot.c edparams.c
$(CC) $(CFLAGS) -DUNIX -c edparams.c
rm edparams.c
edparams: edparams.o rawfs.o
$(CC) $(CFLAGS) $(STRIP) -o $@ edparams.o rawfs.o
install -S 16kw edparams
dosboot.o: boot.c
$(CC86) $(CFLAGS) -DDOS -o $@ -c boot.c
doshead.o: doshead.s
$(CC) -mi386 -o $@ -c doshead.s
dosboot: doshead.o dosboot.o bootimage.o rawfs86.o
$(LD86) -com -o $@ \
doshead.o dosboot.o bootimage.o rawfs86.o $(LIBS)
boot.com: dosboot
./a.out2com dosboot boot.com
mkfile: mkfhead.s mkfile.c
$(LD) -.o -mi86 -com -o $@ mkfhead.s mkfile.c $(LIBS)
mkfile.com: mkfile
./a.out2com mkfile mkfile.com
installboot: installboot.o rawfs.o
$(CC) $(STRIP) -o installboot installboot.o rawfs.o
install -S 6kw installboot
addaout: addaout.o
$(CC) -o addaout addaout.o
installboot.o bootimage.o: image.h
boot.o bootimage.o dosboot.o edparams.o: boot.h
rawfs.o rawfs86.o installboot.o boot.o bootimage.o: rawfs.h
install: $(MDEC)/bootblock $(MDEC)/boot $(MDEC)/masterboot \
$(MDEC)/jumpboot $(BIN)/installboot $(BIN)/edparams
dosinstall: $(MDEC)/boot.com $(MDEC)/mkfile.com
$(MDEC)/bootblock: bootblock
install -cs -o bin -m 644 $? $@
$(MDEC)/boot: boot
install -cs -o bin -m 644 $? $@
$(MDEC)/boot.com: boot.com
install -c -m 644 $? $@
$(MDEC)/mkfile.com: mkfile.com
install -c -m 644 $? $@
$(MDEC)/masterboot: masterboot
install -cs -o bin -m 644 $? $@
$(MDEC)/jumpboot: jumpboot
install -cs -o bin -m 644 $? $@
$(BIN)/installboot: installboot
install -cs -o bin $? $@
$(BIN)/addaout: addaout
install -cs -o bin $? $@
$(BIN)/edparams: edparams
install -cs -o bin $? $@
clean:
rm -f *.bak *.o
rm -f bootblock addaout installboot boot masterboot jumpboot edparams
rm -f dosboot boot.com mkfile mkfile.com

25
boot/a.out2com Executable file
View file

@ -0,0 +1,25 @@
#!/bin/sh
#
# a.out2com - Minix a.out to DOS .COM Author: Kees J. Bot
# 17 Jun 1995
# Transform a Minix a.out to the COM format of MS-DOS,
# the executable must be common I&D with 256 scratch bytes at the start of
# the text segment to make space for the Program Segment Prefix. The Minix
# a.out header and these 256 bytes are removed to make a COM file.
case $# in
2) aout="$1"
com="$2"
;;
*) echo "Usage: $0 <a.out> <dos.com>" >&2
exit 1
esac
size "$aout" >/dev/null || exit
set `size "$aout" | sed 1d`
count=`expr \( $1 + $2 - 256 + 31 \) / 32`
exec dd if="$aout" of="$com" bs=32 skip=9 count=$count conv=silent
#
# $PchId: a.out2com,v 1.3 1998/08/01 09:13:01 philip Exp $

127
boot/addaout.c Normal file
View file

@ -0,0 +1,127 @@
/* A small utility to append an a.out header to an arbitrary file. This allows
* inclusion of arbitrary data in the boot image, so that it is magically
* loaded as a RAM disk. The a.out header is structured as follows:
*
* a_flags: A_IMG to indicate this is not an executable
*
* Created: April 2005, Jorrit N. Herder
*/
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <a.out.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <string.h>
#include <unistd.h>
#define INPUT_FILE 1
#define OUTPUT_FILE 2
/* Report problems. */
void report(char *problem, char *message)
{
fprintf(stderr, "%s:\n", problem);
fprintf(stderr, " %s\n\n", message);
}
int copy_data(int srcfd, int dstfd)
{
char buf[8192];
ssize_t n;
int total=0;
/* Copy the little bytes themselves. (Source from cp.c). */
while ((n= read(srcfd, buf, sizeof(buf))) > 0) {
char *bp = buf;
ssize_t r;
while (n > 0 && (r= write(dstfd, bp, n)) > 0) {
bp += r;
n -= r;
total += r;
}
if (r <= 0) {
if (r == 0) {
fprintf(stderr, "Warning: EOF writing to output file.\n");
return(-1);
}
}
}
return(total);
}
/* Main program. */
int main(int argc, char **argv)
{
struct exec aout;
struct stat stin;
int fdin, fdout;
char * bp;
int n,r;
int total_size=0;
int result;
/* Check if command line arguments are present, or print usage. */
if (argc!=3) {
printf("Invalid arguments. Usage:\n");
printf(" %s <input_file> <output_file>\n",argv[0]);
return(1);
}
/* Check if we can open the input and output file. */
if (stat(argv[INPUT_FILE], &stin) != 0) {
report("Couldn't get status of input file", strerror(errno));
return(1);
}
if ((fdin = open(argv[INPUT_FILE], O_RDONLY)) < 0) {
report("Couldn't open input file", strerror(errno));
return(1);
}
if ((fdout = open(argv[OUTPUT_FILE], O_WRONLY|O_CREAT|O_TRUNC,
stin.st_mode & 0777)) < 0) {
report("Couldn't open output file", strerror(errno));
return(1);
}
/* Copy input file to output file, but leave space for a.out header. */
lseek(fdout, sizeof(aout), SEEK_SET);
total_size = copy_data(fdin, fdout);
if (total_size < 0) {
report("Aborted", "Output file may be truncated.");
return(1);
} else if (total_size == 0) {
report("Aborted without prepending header", "No data in input file.");
return(1);
}
/* Build a.out header and write to output file. */
memset(&aout, 0, sizeof(struct exec));
aout.a_magic[0] = A_MAGIC0;
aout.a_magic[1] = A_MAGIC1;
aout.a_flags |= A_IMG;
aout.a_hdrlen = sizeof(aout);
aout.a_text = 0;
aout.a_data = total_size;
aout.a_bss = 0;
aout.a_total = aout.a_hdrlen + aout.a_data;
bp = (char *) &aout;
n = sizeof(aout);
lseek(fdout, 0, SEEK_SET);
while (n > 0 && (r= write(fdout, bp, n)) > 0) {
bp += r;
n -= r;
}
printf("Prepended data file (%u bytes) with a.out header.\n", total_size);
printf("Done.\n");
return(0);
}

1930
boot/boot.c Executable file

File diff suppressed because it is too large Load diff

209
boot/boot.h Executable file
View file

@ -0,0 +1,209 @@
/* boot.h - Info between different parts of boot. Author: Kees J. Bot
*/
#ifndef DEBUG
#define DEBUG 0
#endif
/* Constants describing the metal: */
#define SECTOR_SIZE 512
#define SECTOR_SHIFT 9
#define RATIO(b) ((b) / SECTOR_SIZE)
#define PARAMSEC 1 /* Sector containing boot parameters. */
#define DSKBASE 0x1E /* Floppy disk parameter vector. */
#define DSKPARSIZE 11 /* There are this many bytes of parameters. */
#define ESC '\33' /* Escape key. */
#define HEADERPOS 0x00600L /* Place for an array of struct exec's. */
#define FREEPOS 0x08000L /* Memory from FREEPOS to caddr is free to
* play with.
*/
#if BIOS
#define MSEC_PER_TICK 55 /* Clock does 18.2 ticks per second. */
#define TICKS_PER_DAY 0x1800B0L /* After 24 hours it wraps. */
#endif
#if UNIX
#define MSEC_PER_TICK 1000 /* Clock does 18.2 ticks per second. */
#define TICKS_PER_DAY 86400L /* Doesn't wrap, but that doesn't matter. */
#endif
#define BOOTPOS 0x07C00L /* Bootstraps are loaded here. */
#define SIGNATURE 0xAA55 /* Proper bootstraps have this signature. */
#define SIGNATOFF 510 /* Offset within bootblock. */
/* BIOS video modes. */
#define MONO_MODE 0x07 /* 80x25 monochrome. */
#define COLOR_MODE 0x03 /* 80x25 color. */
/* Variables shared with boothead.s: */
#ifndef EXTERN
#define EXTERN extern
#endif
typedef struct vector { /* 8086 vector */
u16_t offset;
u16_t segment;
} vector;
EXTERN vector rem_part; /* Boot partition table entry. */
EXTERN u32_t caddr, daddr; /* Code and data address of the boot program. */
EXTERN u32_t runsize; /* Size of this program. */
EXTERN u16_t device; /* Drive being booted from. */
typedef struct { /* One chunk of free memory. */
u32_t base; /* Start byte. */
u32_t size; /* Number of bytes. */
} memory;
EXTERN memory mem[3]; /* List of available memory. */
EXTERN int mon_return; /* Monitor stays in memory? */
typedef struct bios_env
{
u16_t ax;
u16_t bx;
u16_t cx;
u16_t flags;
} bios_env_t;
#define FL_CARRY 0x0001 /* carry flag */
/* Functions defined by boothead.s: */
void exit(int code);
/* Exit the monitor. */
u32_t mon2abs(void *ptr);
/* Local monitor address to absolute address. */
u32_t vec2abs(vector *vec);
/* Vector to absolute address. */
void raw_copy(u32_t dstaddr, u32_t srcaddr, u32_t count);
/* Copy bytes from anywhere to anywhere. */
u16_t get_word(u32_t addr);
/* Get a word from anywhere. */
void put_word(u32_t addr, U16_t word);
/* Put a word anywhere. */
void relocate(void);
/* Switch to a copy of this program. */
int dev_open(void), dev_close(void);
/* Open device and determine params / close device. */
int dev_boundary(u32_t sector);
/* True if sector is on a track boundary. */
int readsectors(u32_t bufaddr, u32_t sector, U8_t count);
/* Read 1 or more sectors from "device". */
int writesectors(u32_t bufaddr, u32_t sector, U8_t count);
/* Write 1 or more sectors to "device". */
int getch(void);
/* Read a keypress. */
void ungetch(int c);
/* Undo a keypress. */
int escape(void);
/* True if escape typed. */
void putch(int c);
/* Send a character to the screen. */
#if BIOS
void pause(void);
/* Wait for an interrupt. */
void serial_init(int line);
#endif /* Enable copying console I/O to a serial line. */
void set_mode(unsigned mode);
void clear_screen(void);
/* Set video mode / clear the screen. */
u16_t get_bus(void);
/* System bus type, XT, AT, or MCA. */
u16_t get_video(void);
/* Display type, MDA to VGA. */
u32_t get_tick(void);
/* Current value of the clock tick counter. */
void bootstrap(int device, struct part_entry *entry);
/* Execute a bootstrap routine for a different O.S. */
void minix(u32_t koff, u32_t kcs, u32_t kds,
char *bootparams, size_t paramsize, u32_t aout);
/* Start Minix. */
void int15(bios_env_t *);
/* Shared between boot.c and bootimage.c: */
/* Sticky attributes. */
#define E_SPECIAL 0x01 /* These are known to the program. */
#define E_DEV 0x02 /* The value is a device name. */
#define E_RESERVED 0x04 /* May not be set by user, e.g. 'boot' */
#define E_STICKY 0x07 /* Don't go once set. */
/* Volatile attributes. */
#define E_VAR 0x08 /* Variable */
#define E_FUNCTION 0x10 /* Function definition. */
/* Variables, functions, and commands. */
typedef struct environment {
struct environment *next;
char flags;
char *name; /* name = value */
char *arg; /* name(arg) {value} */
char *value;
char *defval; /* Safehouse for default values. */
} environment;
EXTERN environment *env; /* Lists the environment. */
char *b_value(char *name); /* Get/set the value of a variable. */
int b_setvar(int flags, char *name, char *value);
void parse_code(char *code); /* Parse boot monitor commands. */
extern int fsok; /* True if the boot device contains an FS. */
EXTERN u32_t lowsec; /* Offset to the file system on the boot device. */
/* Called by boot.c: */
void bootminix(void); /* Load and start a Minix image. */
/* Called by bootimage.c: */
void readerr(off_t sec, int err);
/* Report a read error. */
char *ul2a(u32_t n, unsigned b), *ul2a10(u32_t n);
/* Transform u32_t to ASCII at base b or base 10. */
long a2l(char *a);
/* Cheap atol(). */
unsigned a2x(char *a);
/* ASCII to hex. */
dev_t name2dev(char *name);
/* Translate a device name to a device number. */
int numprefix(char *s, char **ps);
/* True for a numeric prefix. */
int numeric(char *s);
/* True for a numeric string. */
char *unix_err(int err);
/* Give a descriptive text for some UNIX errors. */
int run_trailer(void);
/* Run the trailer function. */
#if DOS
/* The monitor runs under MS-DOS. */
extern char PSP[256]; /* Program Segment Prefix. */
EXTERN char *vdisk; /* Name of the virtual disk. */
EXTERN char *drun; /* Initial command from DOS command line. */
#else
/* The monitor uses only the BIOS. */
#define DOS 0
#endif
void readblock(off_t, char *, int);
/*
* $PchId: boot.h,v 1.12 2002/02/27 19:42:45 philip Exp $
*/

231
boot/bootblock.s Executable file
View file

@ -0,0 +1,231 @@
! Bootblock 1.5 - Minix boot block. Author: Kees J. Bot
! 21 Dec 1991
!
! When the PC is powered on, it will try to read the first sector of floppy
! disk 0 at address 0x7C00. If this fails due to the absence of flexible
! magnetic media, it will read the master boot record from the first sector
! of the hard disk. This sector not only contains executable code, but also
! the partition table of the hard disk. When executed, it will select the
! active partition and load the first sector of that at address 0x7C00.
! This file contains the code that is eventually read from either the floppy
! disk, or the hard disk partition. It is just smart enough to load /boot
! from the boot device into memory at address 0x10000 and execute that. The
! disk addresses for /boot are patched into this code by installboot as 24-bit
! sector numbers and 8-bit sector counts above enddata upwards. /boot is in
! turn smart enough to load the different parts of the Minix kernel into
! memory and execute them to finally get Minix started.
!
LOADOFF = 0x7C00 ! 0x0000:LOADOFF is where this code is loaded
BOOTSEG = 0x1000 ! Secondary boot code segment.
BOOTOFF = 0x0030 ! Offset into /boot above header
BUFFER = 0x0600 ! First free memory
LOWSEC = 8 ! Offset of logical first sector in partition
! table
! Variables addressed using bp register
device = 0 ! The boot device
lowsec = 2 ! Offset of boot partition within drive
secpcyl = 6 ! Sectors per cylinder = heads * sectors
.text
! Start boot procedure.
boot:
xor ax, ax ! ax = 0x0000, the vector segment
mov ds, ax
cli ! Ignore interrupts while setting stack
mov ss, ax ! ss = ds = vector segment
mov sp, #LOADOFF ! Usual place for a bootstrap stack
sti
push ax
push ax ! Push a zero lowsec(bp)
push dx ! Boot device in dl will be device(bp)
mov bp, sp ! Using var(bp) is one byte cheaper then var.
push es
push si ! es:si = partition table entry if hard disk
mov di, #LOADOFF+sectors ! char *di = sectors;
testb dl, dl ! Winchester disks if dl >= 0x80
jge floppy
winchester:
! Get the offset of the first sector of the boot partition from the partition
! table. The table is found at es:si, the lowsec parameter at offset LOWSEC.
eseg
les ax, LOWSEC(si) ! es:ax = LOWSEC+2(si):LOWSEC(si)
mov lowsec+0(bp), ax ! Low 16 bits of partition's first sector
mov lowsec+2(bp), es ! High 16 bits of partition's first sector
! Get the drive parameters, the number of sectors is bluntly written into the
! floppy disk sectors/track array.
movb ah, #0x08 ! Code for drive parameters
int 0x13 ! dl still contains drive
andb cl, #0x3F ! cl = max sector number (1-origin)
movb (di), cl ! Number of sectors per track
incb dh ! dh = 1 + max head number (0-origin)
jmp loadboot
! Floppy:
! Execute three read tests to determine the drive type. Test for each floppy
! type by reading the last sector on the first track. If it fails, try a type
! that has less sectors. Therefore we start with 1.44M (18 sectors) then 1.2M
! (15 sectors) ending with 720K/360K (both 9 sectors).
next: inc di ! Next number of sectors per track
floppy: xorb ah, ah ! Reset drive
int 0x13
movb cl, (di) ! cl = number of last sector on track
cmpb cl, #9 ! No need to do the last 720K/360K test
je success
! Try to read the last sector on track 0
mov es, lowsec(bp) ! es = vector segment (lowsec = 0)
mov bx, #BUFFER ! es:bx buffer = 0x0000:0x0600
mov ax, #0x0201 ! Read sector, #sectors = 1
xorb ch, ch ! Track 0, last sector
xorb dh, dh ! Drive dl, head 0
int 0x13
jc next ! Error, try the next floppy type
success:movb dh, #2 ! Load number of heads for multiply
loadboot:
! Load /boot from the boot device
movb al, (di) ! al = (di) = sectors per track
mulb dh ! dh = heads, ax = heads * sectors
mov secpcyl(bp), ax ! Sectors per cylinder = heads * sectors
mov ax, #BOOTSEG ! Segment to load /boot into
mov es, ax
xor bx, bx ! Load first sector at es:bx = BOOTSEG:0x0000
mov si, #LOADOFF+addresses ! Start of the boot code addresses
load:
mov ax, 1(si) ! Get next sector number: low 16 bits
movb dl, 3(si) ! Bits 16-23 for your up to 8GB partition
xorb dh, dh ! dx:ax = sector within partition
add ax, lowsec+0(bp)
adc dx, lowsec+2(bp)! dx:ax = sector within drive
cmp dx, #[1024*255*63-255]>>16 ! Near 8G limit?
jae bigdisk
div secpcyl(bp) ! ax = cylinder, dx = sector within cylinder
xchg ax, dx ! ax = sector within cylinder, dx = cylinder
movb ch, dl ! ch = low 8 bits of cylinder
divb (di) ! al = head, ah = sector (0-origin)
xorb dl, dl ! About to shift bits 8-9 of cylinder into dl
shr dx, #1
shr dx, #1 ! dl[6..7] = high cylinder
orb dl, ah ! dl[0..5] = sector (0-origin)
movb cl, dl ! cl[0..5] = sector, cl[6..7] = high cyl
incb cl ! cl[0..5] = sector (1-origin)
movb dh, al ! dh = al = head
movb dl, device(bp) ! dl = device to read
movb al, (di) ! Sectors per track - Sector number (0-origin)
subb al, ah ! = Sectors left on this track
cmpb al, (si) ! Compare with # sectors to read
jbe read ! Can't read past the end of a cylinder?
movb al, (si) ! (si) < sectors left on this track
read: push ax ! Save al = sectors to read
movb ah, #0x02 ! Code for disk read (all registers in use now!)
int 0x13 ! Call the BIOS for a read
pop cx ! Restore al in cl
jmp rdeval
bigdisk:
movb cl, (si) ! Number of sectors to read
push si ! Save si
mov si, #LOADOFF+ext_rw ! si = extended read/write parameter packet
movb 2(si), cl ! Fill in # blocks to transfer
mov 4(si), bx ! Buffer address
mov 8(si), ax ! Starting block number = dx:ax
mov 10(si), dx
movb dl, device(bp) ! dl = device to read
movb ah, #0x42 ! Extended read
int 0x13
pop si ! Restore si to point to the addresses array
!jmp rdeval
rdeval:
jc error ! Jump on disk read error
movb al, cl ! Restore al = sectors read
addb bh, al ! bx += 2 * al * 256 (add bytes read)
addb bh, al ! es:bx = where next sector must be read
add 1(si), ax ! Update address by sectors read
adcb 3(si), ah ! Don't forget bits 16-23 (add ah = 0)
subb (si), al ! Decrement sector count by sectors read
jnz load ! Not all sectors have been read
add si, #4 ! Next (address, count) pair
cmpb ah, (si) ! Done when no sectors to read
jnz load ! Read next chunk of /boot
done:
! Call /boot, assuming a long a.out header (48 bytes). The a.out header is
! usually short (32 bytes), but to be sure /boot has two entry points:
! One at offset 0 for the long, and one at offset 16 for the short header.
! Parameters passed in registers are:
!
! dl = Boot-device.
! es:si = Partition table entry if hard disk.
!
pop si ! Restore es:si = partition table entry
pop es ! dl is still loaded
jmpf BOOTOFF, BOOTSEG ! jmp to sec. boot (skipping header).
! Read error: print message, hang forever
error:
mov si, #LOADOFF+errno+1
prnum: movb al, ah ! Error number in ah
andb al, #0x0F ! Low 4 bits
cmpb al, #10 ! A-F?
jb digit ! 0-9!
addb al, #7 ! 'A' - ':'
digit: addb (si), al ! Modify '0' in string
dec si
movb cl, #4 ! Next 4 bits
shrb ah, cl
jnz prnum ! Again if digit > 0
mov si, #LOADOFF+rderr ! String to print
print: lodsb ! al = *si++ is char to be printed
testb al, al ! Null byte marks end
hang: jz hang ! Hang forever waiting for CTRL-ALT-DEL
movb ah, #0x0E ! Print character in teletype mode
mov bx, #0x0001 ! Page 0, foreground color
int 0x10 ! Call BIOS VIDEO_IO
jmp print
.data
rderr: .ascii "Read error "
errno: .ascii "00 \0"
errend:
! Floppy disk sectors per track for the 1.44M, 1.2M and 360K/720K types:
sectors:
.data1 18, 15, 9
! Extended read/write commands require a parameter packet.
ext_rw:
.data1 0x10 ! Length of extended r/w packet
.data1 0 ! Reserved
.data2 0 ! Blocks to transfer (to be filled in)
.data2 0 ! Buffer address offset (tbfi)
.data2 BOOTSEG ! Buffer address segment
.data4 0 ! Starting block number low 32 bits (tbfi)
.data4 0 ! Starting block number high 32 bits
.align 2
addresses:
! The space below this is for disk addresses for a 38K /boot program (worst
! case, i.e. file is completely fragmented). It should be enough.

1497
boot/boothead.s Executable file

File diff suppressed because it is too large Load diff

712
boot/bootimage.c Executable file
View file

@ -0,0 +1,712 @@
/* bootimage.c - Load an image and start it. Author: Kees J. Bot
* 19 Jan 1992
*/
#define BIOS 1 /* Can only be used under the BIOS. */
#define nil 0
#define _POSIX_SOURCE 1
#define _MINIX 1
#include <stddef.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include <errno.h>
#include <a.out.h>
#include <minix/config.h>
#include <minix/const.h>
#include <minix/type.h>
#include <minix/syslib.h>
#include <kernel/const.h>
#include <kernel/type.h>
#include <ibm/partition.h>
#include "rawfs.h"
#include "image.h"
#include "boot.h"
static int block_size = 0;
#define click_shift clck_shft /* 7 char clash with click_size. */
/* Some kernels have extra features: */
#define K_I386 0x0001 /* Make the 386 transition before you call me. */
#define K_CLAIM 0x0002 /* I will acquire my own bss pages, thank you. */
#define K_CHMEM 0x0004 /* This kernel listens to chmem for its stack size. */
#define K_HIGH 0x0008 /* Load mm, fs, etc. in extended memory. */
#define K_HDR 0x0010 /* No need to patch sizes, kernel uses the headers. */
#define K_RET 0x0020 /* Returns to the monitor on reboot. */
#define K_INT86 0x0040 /* Requires generic INT support. */
#define K_MEML 0x0080 /* Pass a list of free memory. */
#define K_BRET 0x0100 /* New monitor code on shutdown in boot parameters. */
#define K_ALL 0x01FF /* All feature bits this monitor supports. */
/* Data about the different processes. */
#define PROCESS_MAX 16 /* Must match the space in kernel/mpx.x */
#define KERNEL 0 /* The first process is the kernel. */
#define FS 2 /* The third must be fs. */
struct process { /* Per-process memory adresses. */
u32_t entry; /* Entry point. */
u32_t cs; /* Code segment. */
u32_t ds; /* Data segment. */
u32_t data; /* To access the data segment. */
u32_t end; /* End of this process, size = (end - cs). */
} process[PROCESS_MAX];
int n_procs; /* Number of processes. */
/* Magic numbers in process' data space. */
#define MAGIC_OFF 0 /* Offset of magic # in data seg. */
#define CLICK_OFF 2 /* Offset in kernel text to click_shift. */
#define FLAGS_OFF 4 /* Offset in kernel text to flags. */
#define KERNEL_D_MAGIC 0x526F /* Kernel magic number. */
/* Offsets of sizes to be patched into kernel and fs. */
#define P_SIZ_OFF 0 /* Process' sizes into kernel data. */
#define P_INIT_OFF 4 /* Init cs & sizes into fs data. */
#define between(a, c, z) ((unsigned) ((c) - (a)) <= ((z) - (a)))
void pretty_image(char *image)
/* Pretty print the name of the image to load. Translate '/' and '_' to
* space, first letter goes uppercase. An 'r' before a digit prints as
* 'revision'. E.g. 'minix/1.6.16r10' -> 'Minix 1.6.16 revision 10'.
* The idea is that the part before the 'r' is the official Minix release
* and after the 'r' you can put version numbers for your own changes.
*/
{
int up= 0, c;
while ((c= *image++) != 0) {
if (c == '/' || c == '_') c= ' ';
if (c == 'r' && between('0', *image, '9')) {
printf(" revision ");
continue;
}
if (!up && between('a', c, 'z')) c= c - 'a' + 'A';
if (between('A', c, 'Z')) up= 1;
putch(c);
}
}
void raw_clear(u32_t addr, u32_t count)
/* Clear "count" bytes at absolute address "addr". */
{
static char zeros[128];
u32_t dst;
u32_t zct;
zct= sizeof(zeros);
if (zct > count) zct= count;
raw_copy(addr, mon2abs(&zeros), zct);
count-= zct;
while (count > 0) {
dst= addr + zct;
if (zct > count) zct= count;
raw_copy(dst, addr, zct);
count-= zct;
zct*= 2;
}
}
/* Align a to a multiple of n (a power of 2): */
#define align(a, n) (((u32_t)(a) + ((u32_t)(n) - 1)) & ~((u32_t)(n) - 1))
unsigned click_shift;
unsigned click_size; /* click_size = Smallest kernel memory object. */
unsigned k_flags; /* Not all kernels are created equal. */
u32_t reboot_code; /* Obsolete reboot code return pointer. */
int params2params(char *params, size_t psize)
/* Repackage the environment settings for the kernel. */
{
size_t i, n;
environment *e;
char *name, *value;
dev_t dev;
i= 0;
for (e= env; e != nil; e= e->next) {
name= e->name;
value= e->value;
if (!(e->flags & E_VAR)) continue;
if (e->flags & E_DEV) {
if ((dev= name2dev(value)) == -1) return 0;
value= ul2a10((u16_t) dev);
}
n= i + strlen(name) + 1 + strlen(value) + 1;
if (n < psize) {
strcpy(params + i, name);
strcat(params + i, "=");
strcat(params + i, value);
}
i= n;
}
if (!(k_flags & K_MEML)) {
/* Require old memory size variables. */
value= ul2a10((mem[0].base + mem[0].size) / 1024);
n= i + 7 + 1 + strlen(value) + 1;
if (n < psize) {
strcpy(params + i, "memsize=");
strcat(params + i, value);
}
i= n;
value= ul2a10(mem[1].size / 1024);
n= i + 7 + 1 + strlen(value) + 1;
if (n < psize) {
strcpy(params + i, "emssize=");
strcat(params + i, value);
}
i= n;
}
if (i >= psize) {
printf("Too many boot parameters\n");
return 0;
}
params[i]= 0; /* End marked with empty string. */
return 1;
}
void patch_sizes(void)
/* Patch sizes of each process into kernel data space, kernel ds into kernel
* text space, and sizes of init into data space of fs. All the patched
* numbers are based on the kernel click size, not hardware segments.
*/
{
u16_t text_size, data_size;
int i;
struct process *procp, *initp;
u32_t doff;
if (k_flags & K_HDR) return; /* Uses the headers. */
/* Patch text and data sizes of the processes into kernel data space.
*/
doff= process[KERNEL].data + P_SIZ_OFF;
for (i= 0; i < n_procs; i++) {
procp= &process[i];
text_size= (procp->ds - procp->cs) >> click_shift;
data_size= (procp->end - procp->ds) >> click_shift;
/* Two words per process, the text and data size: */
put_word(doff, text_size); doff+= 2;
put_word(doff, data_size); doff+= 2;
initp= procp; /* The last process must be init. */
}
if (k_flags & (K_HIGH|K_MEML)) return; /* Doesn't need FS patching. */
/* Patch cs and sizes of init into fs data. */
put_word(process[FS].data + P_INIT_OFF+0, initp->cs >> click_shift);
put_word(process[FS].data + P_INIT_OFF+2, text_size);
put_word(process[FS].data + P_INIT_OFF+4, data_size);
}
int selected(char *name)
/* True iff name has no label or the proper label. */
{
char *colon, *label;
int cmp;
if ((colon= strchr(name, ':')) == nil) return 1;
if ((label= b_value("label")) == nil) return 1;
*colon= 0;
cmp= strcmp(label, name);
*colon= ':';
return cmp == 0;
}
u32_t proc_size(struct image_header *hdr)
/* Return the size of a process in sectors as found in an image. */
{
u32_t len= hdr->process.a_text;
if (hdr->process.a_flags & A_PAL) len+= hdr->process.a_hdrlen;
if (hdr->process.a_flags & A_SEP) len= align(len, SECTOR_SIZE);
len= align(len + hdr->process.a_data, SECTOR_SIZE);
return len >> SECTOR_SHIFT;
}
off_t image_off, image_size;
u32_t (*vir2sec)(u32_t vsec); /* Where is a sector on disk? */
u32_t file_vir2sec(u32_t vsec)
/* Translate a virtual sector number to an absolute disk sector. */
{
off_t blk;
if(!block_size) { errno = 0; return -1; }
if ((blk= r_vir2abs(vsec / RATIO(block_size))) == -1) {
errno= EIO;
return -1;
}
return blk == 0 ? 0 : lowsec + blk * RATIO(block_size) + vsec % RATIO(block_size);
}
u32_t flat_vir2sec(u32_t vsec)
/* Simply add an absolute sector offset to vsec. */
{
return lowsec + image_off + vsec;
}
char *get_sector(u32_t vsec)
/* Read a sector "vsec" from the image into memory and return its address.
* Return nil on error. (This routine tries to read an entire track, so
* the next request is usually satisfied from the track buffer.)
*/
{
u32_t sec;
int r;
static char buf[32 * SECTOR_SIZE];
static size_t count; /* Number of sectors in the buffer. */
static u32_t bufsec; /* First Sector now in the buffer. */
if (vsec == 0) count= 0; /* First sector; initialize. */
if ((sec= (*vir2sec)(vsec)) == -1) return nil;
if (sec == 0) {
/* A hole. */
count= 0;
memset(buf, 0, SECTOR_SIZE);
return buf;
}
/* Can we return a sector from the buffer? */
if ((sec - bufsec) < count) {
return buf + ((size_t) (sec - bufsec) << SECTOR_SHIFT);
}
/* Not in the buffer. */
count= 0;
bufsec= sec;
/* Read a whole track if possible. */
while (++count < 32 && !dev_boundary(bufsec + count)) {
vsec++;
if ((sec= (*vir2sec)(vsec)) == -1) break;
/* Consecutive? */
if (sec != bufsec + count) break;
}
/* Actually read the sectors. */
if ((r= readsectors(mon2abs(buf), bufsec, count)) != 0) {
readerr(bufsec, r);
count= 0;
errno= 0;
return nil;
}
return buf;
}
int get_clickshift(u32_t ksec, struct image_header *hdr)
/* Get the click shift and special flags from kernel text. */
{
char *textp;
if ((textp= get_sector(ksec)) == nil) return 0;
if (hdr->process.a_flags & A_PAL) textp+= hdr->process.a_hdrlen;
click_shift= * (u16_t *) (textp + CLICK_OFF);
k_flags= * (u16_t *) (textp + FLAGS_OFF);
if ((k_flags & ~K_ALL) != 0) {
printf("%s requires features this monitor doesn't offer\n",
hdr->name);
return 0;
}
if (click_shift < HCLICK_SHIFT || click_shift > 16) {
printf("%s click size is bad\n", hdr->name);
errno= 0;
return 0;
}
click_size= 1 << click_shift;
return 1;
}
int get_segment(u32_t *vsec, long *size, u32_t *addr, u32_t limit)
/* Read *size bytes starting at virtual sector *vsec to memory at *addr. */
{
char *buf;
size_t cnt, n;
cnt= 0;
while (*size > 0) {
if (cnt == 0) {
if ((buf= get_sector((*vsec)++)) == nil) return 0;
cnt= SECTOR_SIZE;
}
if (*addr + click_size > limit) { errno= ENOMEM; return 0; }
n= click_size;
if (n > cnt) n= cnt;
raw_copy(*addr, mon2abs(buf), n);
*addr+= n;
*size-= n;
buf+= n;
cnt-= n;
}
/* Zero extend to a click. */
n= align(*addr, click_size) - *addr;
raw_clear(*addr, n);
*addr+= n;
*size-= n;
return 1;
}
void exec_image(char *image)
/* Get a Minix image into core, patch it up and execute. */
{
int i;
struct image_header hdr;
char *buf;
u32_t vsec, addr, limit, aout, n;
struct process *procp; /* Process under construction. */
long a_text, a_data, a_bss, a_stack;
int banner= 0;
long processor= a2l(b_value("processor"));
u16_t mode;
char *console;
char params[SECTOR_SIZE];
extern char *sbrk(int);
/* The stack is pretty deep here, so check if heap and stack collide. */
(void) sbrk(0);
printf("\nLoading ");
pretty_image(image);
printf(".\n\n");
vsec= 0; /* Load this sector from image next. */
addr= mem[0].base; /* Into this memory block. */
limit= mem[0].base + mem[0].size;
if (limit > caddr) limit= caddr;
/* Allocate and clear the area where the headers will be placed. */
aout = (limit -= PROCESS_MAX * A_MINHDR);
/* Clear the area where the headers will be placed. */
raw_clear(aout, PROCESS_MAX * A_MINHDR);
/* Read the many different processes: */
for (i= 0; vsec < image_size; i++) {
if (i == PROCESS_MAX) {
printf("There are more then %d programs in %s\n",
PROCESS_MAX, image);
errno= 0;
return;
}
procp= &process[i];
/* Read header. */
for (;;) {
if ((buf= get_sector(vsec++)) == nil) return;
memcpy(&hdr, buf, sizeof(hdr));
if (BADMAG(hdr.process)) { errno= ENOEXEC; return; }
/* Check the optional label on the process. */
if (selected(hdr.name)) break;
/* Bad label, skip this process. */
vsec+= proc_size(&hdr);
}
/* Sanity check: an 8086 can't run a 386 kernel. */
if (hdr.process.a_cpu == A_I80386 && processor < 386) {
printf("You can't run a 386 kernel on this 80%ld\n",
processor);
errno= 0;
return;
}
/* Get the click shift from the kernel text segment. */
if (i == KERNEL) {
if (!get_clickshift(vsec, &hdr)) return;
addr= align(addr, click_size);
}
/* Save a copy of the header for the kernel, with a_syms
* misused as the address where the process is loaded at.
*/
hdr.process.a_syms= addr;
raw_copy(aout + i * A_MINHDR, mon2abs(&hdr.process), A_MINHDR);
if (!banner) {
printf(" cs ds text data bss");
if (k_flags & K_CHMEM) printf(" stack");
putch('\n');
banner= 1;
}
/* Segment sizes. */
a_text= hdr.process.a_text;
a_data= hdr.process.a_data;
a_bss= hdr.process.a_bss;
if (k_flags & K_CHMEM) {
a_stack= hdr.process.a_total - a_data - a_bss;
if (!(hdr.process.a_flags & A_SEP)) a_stack-= a_text;
} else {
a_stack= 0;
}
/* Collect info about the process to be. */
procp->cs= addr;
/* Process may be page aligned so that the text segment contains
* the header, or have an unmapped zero page against vaxisms.
*/
procp->entry= hdr.process.a_entry;
if (hdr.process.a_flags & A_PAL) a_text+= hdr.process.a_hdrlen;
if (hdr.process.a_flags & A_UZP) procp->cs-= click_size;
/* Separate I&D: two segments. Common I&D: only one. */
if (hdr.process.a_flags & A_SEP) {
/* Read the text segment. */
if (!get_segment(&vsec, &a_text, &addr, limit)) return;
/* The data segment follows. */
procp->ds= addr;
if (hdr.process.a_flags & A_UZP) procp->ds-= click_size;
procp->data= addr;
} else {
/* Add text to data to form one segment. */
procp->data= addr + a_text;
procp->ds= procp->cs;
a_data+= a_text;
}
printf("%06lx %06lx %7ld %7ld %7ld",
procp->cs, procp->ds,
hdr.process.a_text, hdr.process.a_data,
hdr.process.a_bss
);
if (k_flags & K_CHMEM) printf(" %8ld", a_stack);
printf(" %s\n", hdr.name);
/* Read the data segment. */
if (!get_segment(&vsec, &a_data, &addr, limit)) return;
/* Make space for bss and stack unless... */
if (i != KERNEL && (k_flags & K_CLAIM)) a_bss= a_stack= 0;
/* Note that a_data may be negative now, but we can look at it
* as -a_data bss bytes.
*/
/* Compute the number of bss clicks left. */
a_bss+= a_data;
n= align(a_bss, click_size);
a_bss-= n;
/* Zero out bss. */
if (addr + n > limit) { errno= ENOMEM; return; }
raw_clear(addr, n);
addr+= n;
/* And the number of stack clicks. */
a_stack+= a_bss;
n= align(a_stack, click_size);
a_stack-= n;
/* Add space for the stack. */
addr+= n;
/* Process endpoint. */
procp->end= addr;
if (i == 0 && (k_flags & K_HIGH)) {
/* Load the rest in extended memory. */
addr= mem[1].base;
limit= mem[1].base + mem[1].size;
}
}
if ((n_procs= i) == 0) {
printf("There are no programs in %s\n", image);
errno= 0;
return;
}
/* Check the kernel magic number. */
if (get_word(process[KERNEL].data + MAGIC_OFF) != KERNEL_D_MAGIC) {
printf("Kernel magic number is incorrect\n");
errno= 0;
return;
}
/* Patch sizes, etc. into kernel data. */
patch_sizes();
#if !DOS
if (!(k_flags & K_MEML)) {
/* Copy the a.out headers to the old place. */
raw_copy(HEADERPOS, aout, PROCESS_MAX * A_MINHDR);
}
#endif
/* Run the trailer function just before starting Minix. */
if (!run_trailer()) { errno= 0; return; }
/* Translate the boot parameters to what Minix likes best. */
if (!params2params(params, sizeof(params))) { errno= 0; return; }
/* Set the video to the required mode. */
if ((console= b_value("console")) == nil || (mode= a2x(console)) == 0) {
mode= strcmp(b_value("chrome"), "color") == 0 ? COLOR_MODE :
MONO_MODE;
}
set_mode(mode);
/* Close the disk. */
(void) dev_close();
/* Minix. */
minix(process[KERNEL].entry, process[KERNEL].cs,
process[KERNEL].ds, params, sizeof(params), aout);
if (!(k_flags & K_BRET)) {
extern u32_t reboot_code;
raw_copy(mon2abs(params), reboot_code, sizeof(params));
}
parse_code(params);
/* Return from Minix. Things may have changed, so assume nothing. */
fsok= -1;
errno= 0;
}
ino_t latest_version(char *version, struct stat *stp)
/* Recursively read the current directory, selecting the newest image on
* the way up. (One can't use r_stat while reading a directory.)
*/
{
char name[NAME_MAX + 1];
ino_t ino, newest;
time_t mtime;
if ((ino= r_readdir(name)) == 0) { stp->st_mtime= 0; return 0; }
newest= latest_version(version, stp);
mtime= stp->st_mtime;
r_stat(ino, stp);
if (S_ISREG(stp->st_mode) && stp->st_mtime > mtime) {
newest= ino;
strcpy(version, name);
} else {
stp->st_mtime= mtime;
}
return newest;
}
char *select_image(char *image)
/* Look image up on the filesystem, if it is a file then we're done, but
* if its a directory then we want the newest file in that directory. If
* it doesn't exist at all, then see if it is 'number:number' and get the
* image from that absolute offset off the disk.
*/
{
ino_t image_ino;
struct stat st;
image= strcpy(malloc((strlen(image) + 1 + NAME_MAX + 1)
* sizeof(char)), image);
if (fsok == -1) fsok= r_super(&block_size) != 0;
if (!fsok || (image_ino= r_lookup(ROOT_INO, image)) == 0) {
char *size;
if (numprefix(image, &size) && *size++ == ':'
&& numeric(size)) {
vir2sec= flat_vir2sec;
image_off= a2l(image);
image_size= a2l(size);
strcpy(image, "Minix");
return image;
}
if (!fsok)
printf("No image selected\n");
else
printf("Can't load %s: %s\n", image, unix_err(errno));
goto bail_out;
}
r_stat(image_ino, &st);
if (!S_ISREG(st.st_mode)) {
char *version= image + strlen(image);
char dots[NAME_MAX + 1];
if (!S_ISDIR(st.st_mode)) {
printf("%s: %s\n", image, unix_err(ENOTDIR));
goto bail_out;
}
(void) r_readdir(dots);
(void) r_readdir(dots); /* "." & ".." */
*version++= '/';
*version= 0;
if ((image_ino= latest_version(version, &st)) == 0) {
printf("There are no images in %s\n", image);
goto bail_out;
}
r_stat(image_ino, &st);
}
vir2sec= file_vir2sec;
image_size= (st.st_size + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
return image;
bail_out:
free(image);
return nil;
}
void bootminix(void)
/* Load Minix and run it. (Given the size of this program it is surprising
* that it ever gets to that.)
*/
{
char *image;
if ((image= select_image(b_value("image"))) == nil) return;
exec_image(image);
switch (errno) {
case ENOEXEC:
printf("%s contains a bad program header\n", image);
break;
case ENOMEM:
printf("Not enough memory to load %s\n", image);
break;
case EIO:
printf("Unsuspected EOF on %s\n", image);
case 0:
/* No error or error already reported. */;
}
free(image);
}
/*
* $PchId: bootimage.c,v 1.10 2002/02/27 19:39:09 philip Exp $
*/

1369
boot/doshead.s Executable file

File diff suppressed because it is too large Load diff

13
boot/image.h Executable file
View file

@ -0,0 +1,13 @@
/* image.h - Info between installboot and boot. Author: Kees J. Bot
*/
#define IM_NAME_MAX 63
struct image_header {
char name[IM_NAME_MAX + 1]; /* Null terminated. */
struct exec process;
};
/*
* $PchId: image.h,v 1.4 1995/11/27 22:23:12 philip Exp $
*/

833
boot/installboot.c Executable file
View file

@ -0,0 +1,833 @@
/* installboot 3.0 - Make a device bootable Author: Kees J. Bot
* 21 Dec 1991
*
* Either make a device bootable or make an image from kernel, mm, fs, etc.
*/
#define nil 0
#define _POSIX_SOURCE 1
#define _MINIX 1
#include <stdio.h>
#include <stddef.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <dirent.h>
#include <a.out.h>
#include <minix/config.h>
#include <minix/const.h>
#include <minix/partition.h>
#include <minix/u64.h>
#include "rawfs.h"
#include "image.h"
#define BOOTBLOCK 0 /* Of course */
#define SECTOR_SIZE 512 /* Disk sector size. */
#define RATIO(b) ((b)/SECTOR_SIZE)
#define SIGNATURE 0xAA55 /* Boot block signature. */
#define BOOT_MAX 64 /* Absolute maximum size of secondary boot */
#define SIGPOS 510 /* Where to put signature word. */
#define PARTPOS 446 /* Offset to the partition table in a master
* boot block.
*/
#define between(a, c, z) ((unsigned) ((c) - (a)) <= ((z) - (a)))
#define control(c) between('\0', (c), '\37')
#define BOOT_BLOCK_SIZE 1024
void report(char *label)
/* installboot: label: No such file or directory */
{
fprintf(stderr, "installboot: %s: %s\n", label, strerror(errno));
}
void fatal(char *label)
{
report(label);
exit(1);
}
char *basename(char *name)
/* Return the last component of name, stripping trailing slashes from name.
* Precondition: name != "/". If name is prefixed by a label, then the
* label is copied to the basename too.
*/
{
static char base[IM_NAME_MAX];
char *p, *bp= base;
if ((p= strchr(name, ':')) != nil) {
while (name <= p && bp < base + IM_NAME_MAX - 1)
*bp++ = *name++;
}
for (;;) {
if ((p= strrchr(name, '/')) == nil) { p= name; break; }
if (*++p != 0) break;
*--p= 0;
}
while (*p != 0 && bp < base + IM_NAME_MAX - 1) *bp++ = *p++;
*bp= 0;
return base;
}
void bread(FILE *f, char *name, void *buf, size_t len)
/* Read len bytes. Don't dare return without them. */
{
if (len > 0 && fread(buf, len, 1, f) != 1) {
if (ferror(f)) fatal(name);
fprintf(stderr, "installboot: Unexpected EOF on %s\n", name);
exit(1);
}
}
void bwrite(FILE *f, char *name, void *buf, size_t len)
{
if (len > 0 && fwrite(buf, len, 1, f) != 1) fatal(name);
}
long total_text= 0, total_data= 0, total_bss= 0;
int making_image= 0;
void read_header(int talk, char *proc, FILE *procf, struct image_header *ihdr)
/* Read the a.out header of a program and check it. If procf happens to be
* nil then the header is already in *image_hdr and need only be checked.
*/
{
int n, big= 0;
static int banner= 0;
struct exec *phdr= &ihdr->process;
if (procf == nil) {
/* Header already present. */
n= phdr->a_hdrlen;
} else {
memset(ihdr, 0, sizeof(*ihdr));
/* Put the basename of proc in the header. */
strncpy(ihdr->name, basename(proc), IM_NAME_MAX);
/* Read the header. */
n= fread(phdr, sizeof(char), A_MINHDR, procf);
if (ferror(procf)) fatal(proc);
}
if (n < A_MINHDR || BADMAG(*phdr)) {
fprintf(stderr, "installboot: %s is not an executable\n", proc);
exit(1);
}
/* Get the rest of the exec header. */
if (procf != nil) {
bread(procf, proc, ((char *) phdr) + A_MINHDR,
phdr->a_hdrlen - A_MINHDR);
}
if (talk && !banner) {
printf(" text data bss size\n");
banner= 1;
}
if (talk) {
printf("%8ld%8ld%8ld%9ld %s\n",
phdr->a_text, phdr->a_data, phdr->a_bss,
phdr->a_text + phdr->a_data + phdr->a_bss, proc);
}
total_text+= phdr->a_text;
total_data+= phdr->a_data;
total_bss+= phdr->a_bss;
if (phdr->a_cpu == A_I8086) {
long data= phdr->a_data + phdr->a_bss;
if (!(phdr->a_flags & A_SEP)) data+= phdr->a_text;
if (phdr->a_text >= 65536) big|= 1;
if (data >= 65536) big|= 2;
}
if (big) {
fprintf(stderr,
"%s will crash, %s%s%s segment%s larger then 64K\n",
proc,
big & 1 ? "text" : "",
big == 3 ? " and " : "",
big & 2 ? "data" : "",
big == 3 ? "s are" : " is");
}
}
void padimage(char *image, FILE *imagef, int n)
/* Add n zeros to image to pad it to a sector boundary. */
{
while (n > 0) {
if (putc(0, imagef) == EOF) fatal(image);
n--;
}
}
#define align(n) (((n) + ((SECTOR_SIZE) - 1)) & ~((SECTOR_SIZE) - 1))
void copyexec(char *proc, FILE *procf, char *image, FILE *imagef, long n)
/* Copy n bytes from proc to image padded to fill a sector. */
{
int pad, c;
/* Compute number of padding bytes. */
pad= align(n) - n;
while (n > 0) {
if ((c= getc(procf)) == EOF) {
if (ferror(procf)) fatal(proc);
fprintf(stderr, "installboot: premature EOF on %s\n",
proc);
exit(1);
}
if (putc(c, imagef) == EOF) fatal(image);
n--;
}
padimage(image, imagef, pad);
}
void make_image(char *image, char **procv)
/* Collect a set of files in an image, each "segment" is nicely padded out
* to SECTOR_SIZE, so it may be read from disk into memory without trickery.
*/
{
FILE *imagef, *procf;
char *proc, *file;
int procn;
struct image_header ihdr;
struct exec phdr;
struct stat st;
making_image= 1;
if ((imagef= fopen(image, "w")) == nil) fatal(image);
for (procn= 0; (proc= *procv++) != nil; procn++) {
/* Remove the label from the file name. */
if ((file= strchr(proc, ':')) != nil) file++; else file= proc;
/* Real files please, may need to seek. */
if (stat(file, &st) < 0
|| (errno= EISDIR, !S_ISREG(st.st_mode))
|| (procf= fopen(file, "r")) == nil
) fatal(proc);
/* Read a.out header. */
read_header(1, proc, procf, &ihdr);
/* Scratch. */
phdr= ihdr.process;
/* The symbol table is always stripped off. */
ihdr.process.a_syms= 0;
ihdr.process.a_flags &= ~A_NSYM;
/* Write header padded to fill a sector */
bwrite(imagef, image, &ihdr, sizeof(ihdr));
padimage(image, imagef, SECTOR_SIZE - sizeof(ihdr));
/* A page aligned executable needs the header in text. */
if (phdr.a_flags & A_PAL) {
rewind(procf);
phdr.a_text+= phdr.a_hdrlen;
}
/* Copy text and data of proc to image. */
if (phdr.a_flags & A_SEP) {
/* Separate I&D: pad text & data separately. */
copyexec(proc, procf, image, imagef, phdr.a_text);
copyexec(proc, procf, image, imagef, phdr.a_data);
} else {
/* Common I&D: keep text and data together. */
copyexec(proc, procf, image, imagef,
phdr.a_text + phdr.a_data);
}
/* Done with proc. */
(void) fclose(procf);
}
/* Done with image. */
if (fclose(imagef) == EOF) fatal(image);
printf(" ------ ------ ------ -------\n");
printf("%8ld%8ld%8ld%9ld total\n",
total_text, total_data, total_bss,
total_text + total_data + total_bss);
}
void extractexec(FILE *imagef, char *image, FILE *procf, char *proc,
long count, off_t *alen)
/* Copy a segment of an executable. It is padded to a sector in image. */
{
char buf[SECTOR_SIZE];
while (count > 0) {
bread(imagef, image, buf, sizeof(buf));
*alen-= sizeof(buf);
bwrite(procf, proc, buf,
count < sizeof(buf) ? (size_t) count : sizeof(buf));
count-= sizeof(buf);
}
}
void extract_image(char *image)
/* Extract the executables from an image. */
{
FILE *imagef, *procf;
off_t len;
struct stat st;
struct image_header ihdr;
struct exec phdr;
char buf[SECTOR_SIZE];
if (stat(image, &st) < 0) fatal(image);
/* Size of the image. */
len= S_ISREG(st.st_mode) ? st.st_size : -1;
if ((imagef= fopen(image, "r")) == nil) fatal(image);
while (len != 0) {
/* Extract a program, first sector is an extended header. */
bread(imagef, image, buf, sizeof(buf));
len-= sizeof(buf);
memcpy(&ihdr, buf, sizeof(ihdr));
phdr= ihdr.process;
/* Check header. */
read_header(1, ihdr.name, nil, &ihdr);
if ((procf= fopen(ihdr.name, "w")) == nil) fatal(ihdr.name);
if (phdr.a_flags & A_PAL) {
/* A page aligned process contains a header in text. */
phdr.a_text+= phdr.a_hdrlen;
} else {
bwrite(procf, ihdr.name, &ihdr.process, phdr.a_hdrlen);
}
/* Extract text and data segments. */
if (phdr.a_flags & A_SEP) {
extractexec(imagef, image, procf, ihdr.name,
phdr.a_text, &len);
extractexec(imagef, image, procf, ihdr.name,
phdr.a_data, &len);
} else {
extractexec(imagef, image, procf, ihdr.name,
phdr.a_text + phdr.a_data, &len);
}
if (fclose(procf) == EOF) fatal(ihdr.name);
}
}
int rawfd; /* File descriptor to open device. */
char *rawdev; /* Name of device. */
void readblock(off_t blk, char *buf, int block_size)
/* For rawfs, so that it can read blocks. */
{
int n;
if (lseek(rawfd, blk * block_size, SEEK_SET) < 0
|| (n= read(rawfd, buf, block_size)) < 0
) fatal(rawdev);
if (n < block_size) {
fprintf(stderr, "installboot: Unexpected EOF on %s\n", rawdev);
exit(1);
}
}
void writeblock(off_t blk, char *buf, int block_size)
/* Add a function to write blocks for local use. */
{
if (lseek(rawfd, blk * block_size, SEEK_SET) < 0
|| write(rawfd, buf, block_size) < 0
) fatal(rawdev);
}
int raw_install(char *file, off_t *start, off_t *len, int block_size)
/* Copy bootcode or an image to the boot device at the given absolute disk
* block number. This "raw" installation is used to place bootcode and
* image on a disk without a filesystem to make a simple boot disk. Useful
* in automated scripts for J. Random User.
* Note: *len == 0 when an image is read. It is set right afterwards.
*/
{
static char buf[MAX_BLOCK_SIZE]; /* Nonvolatile block buffer. */
FILE *f;
off_t sec;
unsigned long devsize;
static int banner= 0;
struct partition entry;
/* See if the device has a maximum size. */
devsize= -1;
if (ioctl(rawfd, DIOCGETP, &entry) == 0) devsize= cv64ul(entry.size);
if ((f= fopen(file, "r")) == nil) fatal(file);
/* Copy sectors from file onto the boot device. */
sec= *start;
do {
int off= sec % RATIO(BOOT_BLOCK_SIZE);
if (fread(buf + off * SECTOR_SIZE, 1, SECTOR_SIZE, f) == 0)
break;
if (sec >= devsize) {
fprintf(stderr,
"installboot: %s can't be attached to %s\n",
file, rawdev);
return 0;
}
if (off == RATIO(BOOT_BLOCK_SIZE) - 1) writeblock(sec / RATIO(BOOT_BLOCK_SIZE), buf, BOOT_BLOCK_SIZE);
} while (++sec != *start + *len);
if (ferror(f)) fatal(file);
(void) fclose(f);
/* Write a partial block, this may be the last image. */
if (sec % RATIO(BOOT_BLOCK_SIZE) != 0) writeblock(sec / RATIO(BOOT_BLOCK_SIZE), buf, BOOT_BLOCK_SIZE);
if (!banner) {
printf(" sector length\n");
banner= 1;
}
*len= sec - *start;
printf("%8ld%8ld %s\n", *start, *len, file);
*start= sec;
return 1;
}
enum howto { FS, BOOT };
void make_bootable(enum howto how, char *device, char *bootblock,
char *bootcode, char **imagev)
/* Install bootblock on the bootsector of device with the disk addresses to
* bootcode patched into the data segment of bootblock. "How" tells if there
* should or shoudn't be a file system on the disk. The images in the imagev
* vector are added to the end of the device.
*/
{
char buf[MAX_BLOCK_SIZE + 256], *adrp, *parmp;
struct fileaddr {
off_t address;
int count;
} bootaddr[BOOT_MAX + 1], *bap= bootaddr;
struct exec boothdr;
struct image_header dummy;
struct stat st;
ino_t ino;
off_t sector, max_sector;
FILE *bootf;
off_t addr, fssize, pos, len;
char *labels, *label, *image;
int nolabel;
int block_size = 0;
/* Open device and set variables for readblock. */
if ((rawfd= open(rawdev= device, O_RDWR)) < 0) fatal(device);
/* Read and check the superblock. */
fssize= r_super(&block_size);
switch (how) {
case FS:
if (fssize == 0) {
fprintf(stderr,
"installboot: %s is not a Minix file system\n",
device);
exit(1);
}
break;
case BOOT:
if (fssize != 0) {
int s;
printf("%s contains a file system!\n", device);
printf("Scribbling in 10 seconds");
for (s= 0; s < 10; s++) {
fputc('.', stdout);
fflush(stdout);
sleep(1);
}
fputc('\n', stdout);
}
fssize= 1; /* Just a boot block. */
}
if (how == FS) {
/* See if the boot code can be found on the file system. */
if ((ino= r_lookup(ROOT_INO, bootcode)) == 0) {
if (errno != ENOENT) fatal(bootcode);
}
} else {
/* Boot code must be attached at the end. */
ino= 0;
}
if (ino == 0) {
/* For a raw installation, we need to copy the boot code onto
* the device, so we need to look at the file to be copied.
*/
if (stat(bootcode, &st) < 0) fatal(bootcode);
if ((bootf= fopen(bootcode, "r")) == nil) fatal(bootcode);
} else {
/* Boot code is present in the file system. */
r_stat(ino, &st);
/* Get the header from the first block. */
if ((addr= r_vir2abs((off_t) 0)) == 0) {
boothdr.a_magic[0]= !A_MAGIC0;
} else {
readblock(addr, buf, block_size);
memcpy(&boothdr, buf, sizeof(struct exec));
}
bootf= nil;
dummy.process= boothdr;
}
/* See if it is an executable (read_header does the check). */
read_header(0, bootcode, bootf, &dummy);
boothdr= dummy.process;
if (bootf != nil) fclose(bootf);
/* Get all the sector addresses of the secondary boot code. */
max_sector= (boothdr.a_hdrlen + boothdr.a_text
+ boothdr.a_data + SECTOR_SIZE - 1) / SECTOR_SIZE;
if (max_sector > BOOT_MAX * RATIO(block_size)) {
fprintf(stderr, "installboot: %s is way too big\n", bootcode);
exit(0);
}
/* Determine the addresses to the boot code to be patched into the
* boot block.
*/
bap->count= 0; /* Trick to get the address recording going. */
for (sector= 0; sector < max_sector; sector++) {
if (ino == 0) {
addr= fssize + (sector / RATIO(block_size));
} else
if ((addr= r_vir2abs(sector / RATIO(block_size))) == 0) {
fprintf(stderr, "installboot: %s has holes!\n",
bootcode);
exit(1);
}
addr= (addr * RATIO(block_size)) + (sector % RATIO(block_size));
/* First address of the addresses array? */
if (bap->count == 0) bap->address= addr;
/* Paste sectors together in a multisector read. */
if (bap->address + bap->count == addr)
bap->count++;
else {
/* New address. */
bap++;
bap->address= addr;
bap->count= 1;
}
}
(++bap)->count= 0; /* No more. */
/* Get the boot block and patch the pieces in. */
readblock(BOOTBLOCK, buf, BOOT_BLOCK_SIZE);
if ((bootf= fopen(bootblock, "r")) == nil) fatal(bootblock);
read_header(0, bootblock, bootf, &dummy);
boothdr= dummy.process;
if (boothdr.a_text + boothdr.a_data +
4 * (bap - bootaddr) + 1 > PARTPOS) {
fprintf(stderr,
"installboot: %s + addresses to %s don't fit in the boot sector\n",
bootblock, bootcode);
fprintf(stderr,
"You can try copying/reinstalling %s to defragment it\n",
bootcode);
exit(1);
}
/* All checks out right. Read bootblock into the boot block! */
bread(bootf, bootblock, buf, boothdr.a_text + boothdr.a_data);
(void) fclose(bootf);
/* Patch the addresses in. */
adrp= buf + (int) (boothdr.a_text + boothdr.a_data);
for (bap= bootaddr; bap->count != 0; bap++) {
*adrp++= bap->count;
*adrp++= (bap->address >> 0) & 0xFF;
*adrp++= (bap->address >> 8) & 0xFF;
*adrp++= (bap->address >> 16) & 0xFF;
}
/* Zero count stops bootblock's reading loop. */
*adrp++= 0;
if (bap > bootaddr+1) {
printf("%s and %d addresses to %s patched into %s\n",
bootblock, (int)(bap - bootaddr), bootcode, device);
}
/* Boot block signature. */
buf[SIGPOS+0]= (SIGNATURE >> 0) & 0xFF;
buf[SIGPOS+1]= (SIGNATURE >> 8) & 0xFF;
/* Sector 2 of the boot block is used for boot parameters, initially
* filled with null commands (newlines). Initialize it only if
* necessary.
*/
for (parmp= buf + SECTOR_SIZE; parmp < buf + 2*SECTOR_SIZE; parmp++) {
if (*imagev != nil || (control(*parmp) && *parmp != '\n')) {
/* Param sector must be initialized. */
memset(buf + SECTOR_SIZE, '\n', SECTOR_SIZE);
break;
}
}
/* Offset to the end of the file system to add boot code and images. */
pos= fssize * RATIO(block_size);
if (ino == 0) {
/* Place the boot code onto the boot device. */
len= max_sector;
if (!raw_install(bootcode, &pos, &len, block_size)) {
if (how == FS) {
fprintf(stderr,
"\t(Isn't there a copy of %s on %s that can be used?)\n",
bootcode, device);
}
exit(1);
}
}
parmp= buf + SECTOR_SIZE;
nolabel= 0;
if (how == BOOT) {
/* A boot only disk needs to have floppies swapped. */
strcpy(parmp,
"trailer()echo \\nInsert the root diskette then hit RETURN\\n\\w\\c\n");
parmp+= strlen(parmp);
}
while ((labels= *imagev++) != nil) {
/* Place each kernel image on the boot device. */
if ((image= strchr(labels, ':')) != nil)
*image++= 0;
else {
if (nolabel) {
fprintf(stderr,
"installboot: Only one image can be the default\n");
exit(1);
}
nolabel= 1;
image= labels;
labels= nil;
}
len= 0;
if (!raw_install(image, &pos, &len, block_size)) exit(1);
if (labels == nil) {
/* Let this image be the default. */
sprintf(parmp, "image=%ld:%ld\n", pos-len, len);
parmp+= strlen(parmp);
}
while (labels != nil) {
/* Image is prefixed by a comma separated list of
* labels. Define functions to select label and image.
*/
label= labels;
if ((labels= strchr(labels, ',')) != nil) *labels++ = 0;
sprintf(parmp,
"%s(%c){label=%s;image=%ld:%ld;echo %s kernel selected;menu}\n",
label,
between('A', label[0], 'Z')
? label[0]-'A'+'a' : label[0],
label, pos-len, len, label);
parmp+= strlen(parmp);
}
if (parmp > buf + block_size) {
fprintf(stderr,
"installboot: Out of parameter space, too many images\n");
exit(1);
}
}
/* Install boot block. */
writeblock((off_t) BOOTBLOCK, buf, 1024);
if (pos > fssize * RATIO(block_size)) {
/* Tell the total size of the data on the device. */
printf("%16ld (%ld kb) total\n", pos,
(pos + RATIO(block_size) - 1) / RATIO(block_size));
}
}
void install_master(char *device, char *masterboot, char **guide)
/* Booting a hard disk is a two stage process: The master bootstrap in sector
* 0 loads the bootstrap from sector 0 of the active partition which in turn
* starts the operating system. This code installs such a master bootstrap
* on a hard disk. If guide[0] is non-null then the master bootstrap is
* guided into booting a certain device.
*/
{
FILE *masf;
unsigned long size;
struct stat st;
static char buf[MAX_BLOCK_SIZE];
/* Open device. */
if ((rawfd= open(rawdev= device, O_RDWR)) < 0) fatal(device);
/* Open the master boot code. */
if ((masf= fopen(masterboot, "r")) == nil) fatal(masterboot);
/* See if the user is cloning a device. */
if (fstat(fileno(masf), &st) >=0 && S_ISBLK(st.st_mode))
size= PARTPOS;
else {
/* Read and check header otherwise. */
struct image_header ihdr;
read_header(1, masterboot, masf, &ihdr);
size= ihdr.process.a_text + ihdr.process.a_data;
}
if (size > PARTPOS) {
fprintf(stderr, "installboot: %s is too big\n", masterboot);
exit(1);
}
/* Read the master boot block, patch it, write. */
readblock(BOOTBLOCK, buf, BOOT_BLOCK_SIZE);
memset(buf, 0, PARTPOS);
(void) bread(masf, masterboot, buf, size);
if (guide[0] != nil) {
/* Fixate partition to boot. */
char *keys= guide[0];
char *logical= guide[1];
size_t i;
int logfd;
u32_t offset;
struct partition geometry;
/* A string of digits to be seen as keystrokes. */
i= 0;
do {
if (!between('0', keys[i], '9')) {
fprintf(stderr,
"installboot: bad guide keys '%s'\n",
keys);
exit(1);
}
} while (keys[++i] != 0);
if (size + i + 1 > PARTPOS) {
fprintf(stderr,
"installboot: not enough space after '%s' for '%s'\n",
masterboot, keys);
exit(1);
}
memcpy(buf + size, keys, i);
size += i;
buf[size]= '\r';
if (logical != nil) {
if ((logfd= open(logical, O_RDONLY)) < 0
|| ioctl(logfd, DIOCGETP, &geometry) < 0
) {
fatal(logical);
}
offset= div64u(geometry.base, SECTOR_SIZE);
if (size + 5 > PARTPOS) {
fprintf(stderr,
"installboot: not enough space "
"after '%s' for '%s' and an offset "
"to '%s'\n",
masterboot, keys, logical);
exit(1);
}
buf[size]= '#';
memcpy(buf+size+1, &offset, 4);
}
}
/* Install signature. */
buf[SIGPOS+0]= (SIGNATURE >> 0) & 0xFF;
buf[SIGPOS+1]= (SIGNATURE >> 8) & 0xFF;
writeblock(BOOTBLOCK, buf, BOOT_BLOCK_SIZE);
}
void usage(void)
{
fprintf(stderr,
"Usage: installboot -i(mage) image kernel mm fs ... init\n"
" installboot -(e)x(tract) image\n"
" installboot -d(evice) device bootblock boot [image ...]\n"
" installboot -b(oot) device bootblock boot image ...\n"
" installboot -m(aster) device masterboot [keys [logical]]\n");
exit(1);
}
int isoption(char *option, char *test)
/* Check if the option argument is equals "test". Also accept -i as short
* for -image, and the special case -x for -extract.
*/
{
if (strcmp(option, test) == 0) return 1;
if (option[0] != '-' && strlen(option) != 2) return 0;
if (option[1] == test[1]) return 1;
if (option[1] == 'x' && test[1] == 'e') return 1;
return 0;
}
int main(int argc, char **argv)
{
if (argc < 2) usage();
if (argc >= 4 && isoption(argv[1], "-image")) {
make_image(argv[2], argv + 3);
} else
if (argc == 3 && isoption(argv[1], "-extract")) {
extract_image(argv[2]);
} else
if (argc >= 5 && isoption(argv[1], "-device")) {
make_bootable(FS, argv[2], argv[3], argv[4], argv + 5);
} else
if (argc >= 6 && isoption(argv[1], "-boot")) {
make_bootable(BOOT, argv[2], argv[3], argv[4], argv + 5);
} else
if ((4 <= argc && argc <= 6) && isoption(argv[1], "-master")) {
install_master(argv[2], argv[3], argv + 4);
} else {
usage();
}
exit(0);
}
/*
* $PchId: installboot.c,v 1.10 2000/08/13 22:07:50 philip Exp $
*/

261
boot/jumpboot.s Executable file
View file

@ -0,0 +1,261 @@
! jumpboot 1.0 - Jump to another bootstrap Author: Kees J. Bot
! 14 Apr 1999
!
! This code may be placed into any free boot sector, like the first sector
! of an extended partition, a file system partition other than the root,
! or even the master bootstrap. It will load and run another bootstrap whose
! disk, partition, and slice number (not necessarily all three) are patched
! into this code by installboot. If the ALT key is held down when this code
! is booted then you can type the disk, partition, and slice numbers manually.
! The manual interface is default if no numbers are patched in by installboot.
!
o32 = 0x66 ! This assembler doesn't know 386 extensions
LOADOFF = 0x7C00 ! 0x0000:LOADOFF is where this code is loaded
BUFFER = 0x0600 ! First free memory
PART_TABLE = 446 ! Location of partition table within master
PENTRYSIZE = 16 ! Size of one partition table entry
MAGIC = 510 ! Location of the AA55 magic number
! <ibm/partition.h>:
MINIX_PART = 0x81
sysind = 4
lowsec = 8
.text
! Find and load another bootstrap and jump to it.
jumpboot:
xor ax, ax
mov ds, ax
mov es, ax
cli
mov ss, ax ! ds = es = ss = Vector segment
mov sp, #LOADOFF
sti
! Move this code to safety, then jump to it.
mov si, sp ! si = start of this code
mov di, #BUFFER ! di = Buffer area
mov cx, #512/2 ! One sector
cld
rep movs
jmpf BUFFER+migrate, 0 ! To safety
migrate:
mov bp, #BUFFER+guide ! Patched guiding characters
altkey:
movb ah, #0x02 ! Keyboard shift status
int 0x16
testb al, #0x08 ! Bit 3 = ALT key
jz noalt ! ALT key pressed?
again:
mov bp, #zero ! Ignore patched stuff
noalt:
! Follow guide characters to find the boot partition.
call print
.ascii "d?\b\0" ! Initial greeting
! Disk number?
disk:
movb dl, #0x80 - 0x30 ! Prepare to add an ASCII digit
call getch ! Get number to tell which disk
addb dl, al ! dl = 0x80 + (al - '0')
jns n0nboot ! Result should be >= 0x80
mov si, #BUFFER+zero-lowsec ! si = where lowsec(si) is zero
cmpb (bp), #0x23 ! Next guide character is '#'?
jne notlogical
lea si, 1-lowsec(bp) ! Logical sector offset follows '#'
notlogical:
call load ! Load chosen sector of chosen disk
cmpb (bp), #0x23
je boot ! Run bootstrap if a logical is chosen
call print ! Intro to partition number
.ascii "p?\b\0"
part:
call getch ! Get character to tell partition
call gettable ! Get partition table
call sort ! Sort partition table
call choose_load ! Compute chosen entry and load
cmpb sysind(si), #MINIX_PART ! Minix subpartition table possible?
jne waitboot
call print ! Intro to slice number
.ascii "s?\b\0"
slice:
call getch ! Get character to tell slice
call gettable ! Get partition table
call choose_load ! Compute chosen entry and load
waitboot:
call print ! Intro to nothing
.ascii " ?\b\0"
call getch ! Supposed to type RETURN now
n0nboot:jmp nonboot ! Sorry, can't go further
! Get a character, either the patched-in, or one from the keyboard.
getch:
movb al, (bp) ! Get patched-in character
testb al, al
jz getkey
inc bp
jmp gotkey
getkey: xorb ah, ah ! Wait for keypress
int 0x16
gotkey: testb dl, dl ! Ignore CR if disk number not yet set
jns putch
cmpb al, #0x0D ! Carriage return?
je boot
!jmp putch
! Print a character
putch: movb ah, #0x0E ! Print character in teletype mode
mov bx, #0x0001 ! Page 0, foreground color
int 0x10
ret
! Print a message.
print: mov cx, si ! Save si
pop si ! si = String following 'call print'
prnext: lodsb ! al = *si++ is char to be printed
testb al, al ! Null marks end
jz prdone
call putch
jmp prnext
prdone: xchg si, cx ! Restore si
jmp (cx) ! Continue after the string
! Return typed (or in patched data) means to run the bootstrap now in core!
boot:
call print ! Make line on screen look proper
.ascii "\b \r\n\0"
jmp LOADOFF-BUFFER ! Jump to LOADOFF
! Compute address of chosen partition entry from choice al into si, then
! continue to load the boot sector of that partition.
choose_load:
subb al, #0x30 ! al -= '0'
cmpb al, #4 ! Only four partitions
ja n0nboot
movb ah, #PENTRYSIZE
mulb ah ! al *= PENTRYSIZE
add ax, #BUFFER+PART_TABLE
mov si, ax ! si = &part_table[al - '0']
movb al, sysind(si) ! System indicator
testb al, al ! Unused partition?
jz n0nboot
!jmp load ! Continue to load boot sector
! Load boot sector of the current partition.
load:
push dx ! Save drive code
push es ! Next call sets es
movb ah, #0x08 ! Code for drive parameters
int 0x13
pop es
andb cl, #0x3F ! cl = max sector number (1-origin)
incb dh ! dh = 1 + max head number (0-origin)
movb al, cl ! al = cl = sectors per track
mulb dh ! dh = heads, ax = heads * sectors
mov bx, ax ! bx = sectors per cylinder = heads * sectors
mov ax, lowsec+0(si)
mov dx, lowsec+2(si) ! dx:ax = sector within drive
cmp dx, #[1024*255*63-255]>>16 ! Near 8G limit?
jae bigdisk
div bx ! ax = cylinder, dx = sector within cylinder
xchg ax, dx ! ax = sector within cylinder, dx = cylinder
movb ch, dl ! ch = low 8 bits of cylinder
divb cl ! al = head, ah = sector (0-origin)
xorb dl, dl ! About to shift bits 8-9 of cylinder into dl
shr dx, #1
shr dx, #1 ! dl[6..7] = high cylinder
orb dl, ah ! dl[0..5] = sector (0-origin)
movb cl, dl ! cl[0..5] = sector, cl[6..7] = high cyl
incb cl ! cl[0..5] = sector (1-origin)
pop dx ! Restore drive code in dl
movb dh, al ! dh = al = head
mov bx, #LOADOFF ! es:bx = where sector is loaded
mov ax, #0x0201 ! ah = Code for read / al = one sector
int 0x13
jmp rdeval ! Evaluate read result
bigdisk:
mov bx, dx ! bx:ax = dx:ax = sector to read
pop dx ! Restore drive code in dl
push si ! Save si
mov si, #BUFFER+ext_rw ! si = extended read/write parameter packet
mov 8(si), ax ! Starting block number = bx:ax
mov 10(si), bx
movb ah, #0x42 ! Extended read
int 0x13
pop si ! Restore si to point to partition entry
!jmp rdeval
rdeval:
jnc rdok
rderr:
call print
.ascii "\r\nRead error\r\n\0"
jmp again
rdok:
cmp LOADOFF+MAGIC, #0xAA55
je sigok ! Signature ok?
nonboot:
call print
.ascii "\r\nNot bootable\r\n\0"
jmp again
sigok:
ret
! Get the partition table into my space.
gettable:
mov si, #LOADOFF+PART_TABLE
mov di, #BUFFER+PART_TABLE
mov cx, #4*PENTRYSIZE/2
rep movs
ret
! Sort the partition table.
sort:
mov cx, #4 ! Four times is enough to sort
bubble: mov si, #BUFFER+PART_TABLE ! First table entry
bubble1:lea di, PENTRYSIZE(si) ! Next entry
cmpb sysind(si), ch ! Partition type, nonzero when in use
jz exchg ! Unused entries sort to the end
inuse: mov bx, lowsec+0(di)
sub bx, lowsec+0(si) ! Compute di->lowsec - si->lowsec
mov bx, lowsec+2(di)
sbb bx, lowsec+2(si)
jae order ! In order if si->lowsec <= di->lowsec
exchg: movb bl, (si)
xchgb bl, PENTRYSIZE(si) ! Exchange entries byte by byte
movb (si), bl
inc si
cmp si, di
jb exchg
order: mov si, di
cmp si, #BUFFER+PART_TABLE+3*PENTRYSIZE
jb bubble1
loop bubble
ret
.data
! Extended read/write commands require a parameter packet.
ext_rw:
.data1 0x10 ! Length of extended r/w packet
.data1 0 ! Reserved
.data2 1 ! Blocks to transfer (just one)
.data2 LOADOFF ! Buffer address offset
.data2 0 ! Buffer address segment
.data4 0 ! Starting block number low 32 bits (tbfi)
zero: .data4 0 ! Starting block number high 32 bits
.align 2
guide:
! Guide characters and possibly a logical partition number patched here by
! installboot, up to 6 bytes maximum.

218
boot/masterboot.s Executable file
View file

@ -0,0 +1,218 @@
! masterboot 2.0 - Master boot block code Author: Kees J. Bot
!
! This code may be placed in the first sector (the boot sector) of a floppy,
! hard disk or hard disk primary partition. There it will perform the
! following actions at boot time:
!
! - If the booted device is a hard disk and one of the partitions is active
! then the active partition is booted.
!
! - Otherwise the next floppy or hard disk device is booted, trying them one
! by one.
!
! To make things a little clearer, the boot path might be:
! /dev/fd0 - Floppy disk containing data, tries fd1 then d0
! [/dev/fd1] - Drive empty
! /dev/c0d0 - Master boot block, selects active partition 2
! /dev/c0d0p2 - Submaster, selects active subpartition 0
! /dev/c0d0p2s0 - Minix bootblock, reads Boot Monitor /boot
! Minix - Started by /boot from a kernel image in /minix
LOADOFF = 0x7C00 ! 0x0000:LOADOFF is where this code is loaded
BUFFER = 0x0600 ! First free memory
PART_TABLE = 446 ! Location of partition table within this code
PENTRYSIZE = 16 ! Size of one partition table entry
MAGIC = 510 ! Location of the AA55 magic number
! <ibm/partition>.h:
bootind = 0
sysind = 4
lowsec = 8
.text
! Find active (sub)partition, load its first sector, run it.
master:
xor ax, ax
mov ds, ax
mov es, ax
cli
mov ss, ax ! ds = es = ss = Vector segment
mov sp, #LOADOFF
sti
! Copy this code to safety, then jump to it.
mov si, sp ! si = start of this code
push si ! Also where we'll return to eventually
mov di, #BUFFER ! Buffer area
mov cx, #512/2 ! One sector
cld
rep movs
jmpf BUFFER+migrate, 0 ! To safety
migrate:
! Find the active partition
findactive:
testb dl, dl
jns nextdisk ! No bootable partitions on floppies
mov si, #BUFFER+PART_TABLE
find: cmpb sysind(si), #0 ! Partition type, nonzero when in use
jz nextpart
testb bootind(si), #0x80 ! Active partition flag in bit 7
jz nextpart ! It's not active
loadpart:
call load ! Load partition bootstrap
jc error1 ! Not supposed to fail
bootstrap:
ret ! Jump to the master bootstrap
nextpart:
add si, #PENTRYSIZE
cmp si, #BUFFER+PART_TABLE+4*PENTRYSIZE
jb find
! No active partition, tell 'em
call print
.ascii "No active partition\0"
jmp reboot
! There are no active partitions on this drive, try the next drive.
nextdisk:
incb dl ! Increment dl for the next drive
testb dl, dl
js nexthd ! Hard disk if negative
int 0x11 ! Get equipment configuration
shl ax, #1 ! Highest floppy drive # in bits 6-7
shl ax, #1 ! Now in bits 0-1 of ah
andb ah, #0x03 ! Extract bits
cmpb dl, ah ! Must be dl <= ah for drive to exist
ja nextdisk ! Otherwise try disk 0 eventually
call load0 ! Read the next floppy bootstrap
jc nextdisk ! It failed, next disk please
ret ! Jump to the next master bootstrap
nexthd: call load0 ! Read the hard disk bootstrap
error1: jc error ! No disk?
ret
! Load sector 0 from the current device. It's either a floppy bootstrap or
! a hard disk master bootstrap.
load0:
mov si, #BUFFER+zero-lowsec ! si = where lowsec(si) is zero
!jmp load
! Load sector lowsec(si) from the current device. The obvious head, sector,
! and cylinder numbers are ignored in favour of the more trustworthy absolute
! start of partition.
load:
mov di, #3 ! Three retries for floppy spinup
retry: push dx ! Save drive code
push es
push di ! Next call destroys es and di
movb ah, #0x08 ! Code for drive parameters
int 0x13
pop di
pop es
andb cl, #0x3F ! cl = max sector number (1-origin)
incb dh ! dh = 1 + max head number (0-origin)
movb al, cl ! al = cl = sectors per track
mulb dh ! dh = heads, ax = heads * sectors
mov bx, ax ! bx = sectors per cylinder = heads * sectors
mov ax, lowsec+0(si)
mov dx, lowsec+2(si)! dx:ax = sector within drive
cmp dx, #[1024*255*63-255]>>16 ! Near 8G limit?
jae bigdisk
div bx ! ax = cylinder, dx = sector within cylinder
xchg ax, dx ! ax = sector within cylinder, dx = cylinder
movb ch, dl ! ch = low 8 bits of cylinder
divb cl ! al = head, ah = sector (0-origin)
xorb dl, dl ! About to shift bits 8-9 of cylinder into dl
shr dx, #1
shr dx, #1 ! dl[6..7] = high cylinder
orb dl, ah ! dl[0..5] = sector (0-origin)
movb cl, dl ! cl[0..5] = sector, cl[6..7] = high cyl
incb cl ! cl[0..5] = sector (1-origin)
pop dx ! Restore drive code in dl
movb dh, al ! dh = al = head
mov bx, #LOADOFF ! es:bx = where sector is loaded
mov ax, #0x0201 ! Code for read, just one sector
int 0x13 ! Call the BIOS for a read
jmp rdeval ! Evaluate read result
bigdisk:
mov bx, dx ! bx:ax = dx:ax = sector to read
pop dx ! Restore drive code in dl
push si ! Save si
mov si, #BUFFER+ext_rw ! si = extended read/write parameter packet
mov 8(si), ax ! Starting block number = bx:ax
mov 10(si), bx
movb ah, #0x42 ! Extended read
int 0x13
pop si ! Restore si to point to partition entry
!jmp rdeval
rdeval:
jnc rdok ! Read succeeded
cmpb ah, #0x80 ! Disk timed out? (Floppy drive empty)
je rdbad
dec di
jl rdbad ! Retry count expired
xorb ah, ah
int 0x13 ! Reset
jnc retry ! Try again
rdbad: stc ! Set carry flag
ret
rdok: cmp LOADOFF+MAGIC, #0xAA55
jne nosig ! Error if signature wrong
ret ! Return with carry still clear
nosig: call print
.ascii "Not bootable\0"
jmp reboot
! A read error occurred, complain and hang
error:
mov si, #LOADOFF+errno+1
prnum: movb al, ah ! Error number in ah
andb al, #0x0F ! Low 4 bits
cmpb al, #10 ! A-F?
jb digit ! 0-9!
addb al, #7 ! 'A' - ':'
digit: addb (si), al ! Modify '0' in string
dec si
movb cl, #4 ! Next 4 bits
shrb ah, cl
jnz prnum ! Again if digit > 0
call print
.ascii "Read error "
errno: .ascii "00\0"
!jmp reboot
reboot:
call print
.ascii ". Hit any key to reboot.\0"
xorb ah, ah ! Wait for keypress
int 0x16
call print
.ascii "\r\n\0"
int 0x19
! Print a message.
print: pop si ! si = String following 'call print'
prnext: lodsb ! al = *si++ is char to be printed
testb al, al ! Null marks end
jz prdone
movb ah, #0x0E ! Print character in teletype mode
mov bx, #0x0001 ! Page 0, foreground color
int 0x10
jmp prnext
prdone: jmp (si) ! Continue after the string
.data
! Extended read/write commands require a parameter packet.
ext_rw:
.data1 0x10 ! Length of extended r/w packet
.data1 0 ! Reserved
.data2 1 ! Blocks to transfer (just one)
.data2 LOADOFF ! Buffer address offset
.data2 0 ! Buffer address segment
.data4 0 ! Starting block number low 32 bits (tbfi)
zero: .data4 0 ! Starting block number high 32 bits

137
boot/mkfhead.s Executable file
View file

@ -0,0 +1,137 @@
! Mkfhead.s - DOS & BIOS support for mkfile.c Author: Kees J. Bot
! 9 May 1998
!
! This file contains the startup and low level support for the MKFILE.COM
! utility. See doshead.ack.s for more comments on .COM files.
!
.sect .text; .sect .rom; .sect .data; .sect .bss
.sect .text
.define _PSP
_PSP:
.space 256 ! Program Segment Prefix
mkfile:
cld ! C compiler wants UP
xor ax, ax ! Zero
mov di, _edata ! Start of bss is at end of data
mov cx, _end ! End of bss (begin of heap)
sub cx, di ! Number of bss bytes
shr cx, 1 ! Number of words
rep stos ! Clear bss
xor cx, cx ! cx = argc
xor bx, bx
push bx ! argv[argc] = NULL
movb bl, (_PSP+0x80) ! Argument byte count
0: movb _PSP+0x81(bx), ch ! Null terminate
dec bx
js 9f
cmpb _PSP+0x81(bx), 0x20 ! Whitespace?
jbe 0b
1: dec bx ! One argument character
js 2f
cmpb _PSP+0x81(bx), 0x20 ! More argument characters?
ja 1b
2: lea ax, _PSP+0x81+1(bx) ! Address of argument
push ax ! argv[n]
inc cx ! argc++;
test bx, bx
jns 0b ! More arguments?
9: movb _PSP+0x81(bx), ch ! Make a null string
lea ax, _PSP+0x81(bx)
push ax ! to use as argv[0]
inc cx ! Final value of argc
mov ax, sp
push ax ! argv
push cx ! argc
call _main ! main(argc, argv)
push ax
call _exit ! exit(main(argc, argv))
! int creat(const char *path, mode_t mode)
! Create a file with the old creat() call.
.define _creat
_creat:
mov bx, sp
mov dx, 2(bx) ! Filename
xor cx, cx ! Ignore mode, always read-write
movb ah, 0x3C ! "CREAT"
dos: int 0x21 ! ax = creat(path, 0666);
jc seterrno
ret
seterrno:
mov (_errno), ax ! Set errno to the DOS error code
mov ax, -1
cwd ! return -1L;
ret
! int open(const char *path, int oflag)
! Open a file with the oldfashioned two-argument open() call.
.define _open
_open:
mov bx, sp
mov dx, 2(bx) ! Filename
movb al, 4(bx) ! O_RDONLY, O_WRONLY, O_RDWR
movb ah, 0x3D ! "OPEN"
jmp dos
! int close(int fd)
! Close an open file.
.define _close
_close:
mov bx, sp
mov bx, 2(bx) ! bx = file handle
movb ah, 0x3E ! "CLOSE"
jmp dos
! void exit(int status)
! void _exit(int status)
! Return to DOS.
.define _exit, __exit, ___exit
_exit:
__exit:
___exit:
pop ax
pop ax ! al = status
movb ah, 0x4C ! "EXIT"
int 0x21
hlt
! ssize_t read(int fd, void *buf, size_t n)
! Read bytes from an open file.
.define _read
_read:
mov bx, sp
mov cx, 6(bx)
mov dx, 4(bx)
mov bx, 2(bx)
movb ah, 0x3F ! "READ"
jmp dos
! ssize_t write(int fd, const void *buf, size_t n)
! Write bytes to an open file.
.define _write
_write:
mov bx, sp
mov cx, 6(bx)
mov dx, 4(bx)
mov bx, 2(bx)
movb ah, 0x40 ! "WRITE"
jmp dos
! off_t lseek(int fd, off_t offset, int whence)
! Set file position for read or write.
.define _lseek
_lseek:
mov bx, sp
movb al, 8(bx) ! SEEK_SET, SEEK_CUR, SEEK_END
mov dx, 4(bx)
mov cx, 6(bx) ! cx:dx = offset
mov bx, 2(bx)
movb ah, 0x42 ! "LSEEK"
jmp dos
!
! $PchId: mkfhead.ack.s,v 1.3 1999/01/14 21:17:06 philip Exp $

180
boot/mkfile.c Executable file
View file

@ -0,0 +1,180 @@
/* mkfile 1.0 - create a file under DOS for use as a Minix "disk".
* Author: Kees J. Bot
* 9 May 1998
*/
#define nil 0
#include <sys/types.h>
#include <string.h>
#include <limits.h>
/* Stuff normally found in <unistd.h>, <errno.h>, etc. */
extern int errno;
int creat(const char *file, int mode);
int open(const char *file, int oflag);
off_t lseek(int fd, off_t offset, int whence);
ssize_t write(int fd, const char *buf, size_t len);
void exit(int status);
int printf(const char *fmt, ...);
#define O_WRONLY 1
#define SEEK_SET 0
#define SEEK_END 2
/* Kernel printf requires a putk() function. */
int putk(int c)
{
char ch = c;
if (c == 0) return;
if (c == '\n') putk('\r');
(void) write(2, &ch, 1);
}
static void usage(void)
{
printf("Usage: mkfile <size>[gmk] <file>\n"
"(Example sizes, all 50 meg: 52428800, 51200k, 50m)\n");
exit(1);
}
char *strerror(int err)
/* Translate some DOS error numbers to text. */
{
static struct errlist {
int err;
char *what;
} errlist[] = {
{ 0, "No error" },
{ 1, "Function number invalid" },
{ 2, "File not found" },
{ 3, "Path not found" },
{ 4, "Too many open files" },
{ 5, "Access denied" },
{ 6, "Invalid handle" },
{ 12, "Access code invalid" },
{ 39, "Insufficient disk space" },
};
struct errlist *ep;
static char unknown[]= "Error 65535";
unsigned e;
char *p;
for (ep= errlist; ep < errlist + sizeof(errlist)/sizeof(errlist[0]);
ep++) {
if (ep->err == err) return ep->what;
}
p= unknown + sizeof(unknown) - 1;
e= err;
do *--p= '0' + (e % 10); while ((e /= 10) > 0);
strcpy(unknown + 6, p);
return unknown;
}
int main(int argc, char **argv)
{
int i;
static char buf[512];
unsigned long size, mul;
off_t offset;
char *cp;
int fd;
char *file;
if (argc != 3) usage();
cp= argv[1];
size= 0;
while ((unsigned) (*cp - '0') < 10) {
unsigned d= *cp++ - '0';
if (size <= (ULONG_MAX-9) / 10) {
size= size * 10 + d;
} else {
size= ULONG_MAX;
}
}
if (cp == argv[1]) usage();
while (*cp != 0) {
mul = 1;
switch (*cp++) {
case 'G':
case 'g': mul *= 1024;
case 'M':
case 'm': mul *= 1024;
case 'K':
case 'k': mul *= 1024;
case 'B':
case 'b': break;
default: usage();
}
if (size <= ULONG_MAX / mul) {
size *= mul;
} else {
size= ULONG_MAX;
}
}
if (size > 1024L*1024*1024) {
printf("mkfile: A file size over 1G is a bit too much\n");
exit(1);
}
/* Open existing file, or create a new file. */
file= argv[2];
if ((fd= open(file, O_WRONLY)) < 0) {
if (errno == 2) {
fd= creat(file, 0666);
}
}
if (fd < 0) {
printf("mkfile: Can't open %s: %s\n", file, strerror(errno));
exit(1);
}
/* How big is the file now? */
if ((offset= lseek(fd, 0, SEEK_END)) == -1) {
printf("mkfile: Can't seek in %s: %s\n", file, strerror(errno));
exit(1);
}
if (offset == 0 && size == 0) exit(0); /* Huh? */
/* Write the first bit if the file is zero length. This is necessary
* to circumvent a DOS bug by extending a new file by lseek. We also
* want to make sure there are zeros in the first sector.
*/
if (offset == 0) {
if (write(fd, buf, sizeof(buf)) == -1) {
printf("mkfile: Can't write to %s: %s\n",
file, strerror(errno));
exit(1);
}
}
/* Seek to the required size and write 0 bytes to extend/truncate the
* file to that size.
*/
if (lseek(fd, size, SEEK_SET) == -1) {
printf("mkfile: Can't seek in %s: %s\n", file, strerror(errno));
exit(1);
}
if (write(fd, buf, 0) == -1) {
printf("mkfile: Can't write to %s: %s\n",
file, strerror(errno));
exit(1);
}
/* Did the file become the required size? */
if ((offset= lseek(fd, 0, SEEK_END)) == -1) {
printf("mkfile: Can't seek in %s: %s\n", file, strerror(errno));
exit(1);
}
if (offset != size) {
printf("mkfile: Failed to extend %s. Disk full?\n", file);
exit(1);
}
return 0;
}
/*
* $PchId: mkfile.c,v 1.4 2000/08/13 22:06:40 philip Exp $
*/

350
boot/rawfs.c Executable file
View file

@ -0,0 +1,350 @@
/* rawfs.c - Raw Minix file system support. Author: Kees J. Bot
* 23 Dec 1991
* Based on readfs by Paul Polderman
*/
#define nil 0
#define _POSIX_SOURCE 1
#define _MINIX 1
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include <errno.h>
#include <minix/config.h>
#include <minix/const.h>
#include <minix/type.h>
#include <servers/fs/const.h>
#include <servers/fs/type.h>
#include <servers/fs/buf.h>
#include <servers/fs/super.h>
#include <servers/fs/inode.h>
#include "rawfs.h"
void readblock(off_t blockno, char *buf, int);
/* The following code handles two file system types: Version 1 with small
* inodes and 16-bit disk addresses and Version 2 with big inodes and 32-bit
* disk addresses.
#ifdef FLEX
* To make matters worse, Minix-vmd knows about the normal Unix Version 7
* directories and directories with flexible entries.
#endif
*/
/* File system parameters. */
static unsigned nr_dzones; /* Fill these in after reading superblock. */
static unsigned nr_indirects;
static unsigned inodes_per_block;
static int block_size;
#ifdef FLEX
#include <dirent.h>
#define direct _v7_direct
#else
#include <sys/dir.h>
#endif
#if __minix_vmd
static struct v12_super_block super; /* Superblock of file system */
#define s_log_zone_size s_dummy /* Zones are obsolete. */
#else
static struct super_block super; /* Superblock of file system */
#define SUPER_V1 SUPER_MAGIC /* V1 magic has a weird name. */
#endif
#define RAWFS_MAX_BLOCK_SIZE 1024
static struct inode curfil; /* Inode of file under examination */
static char indir[RAWFS_MAX_BLOCK_SIZE]; /* Single indirect block. */
static char dindir[RAWFS_MAX_BLOCK_SIZE]; /* Double indirect block. */
static char dirbuf[RAWFS_MAX_BLOCK_SIZE]; /* Scratch/Directory block. */
#define scratch dirbuf
static block_t a_indir, a_dindir; /* Addresses of the indirects. */
static off_t dirpos; /* Reading pos in a dir. */
#define fsbuf(b) (* (struct buf *) (b))
#define zone_shift (super.s_log_zone_size) /* zone to block ratio */
off_t r_super(int *bs)
/* Initialize variables, return size of file system in blocks,
* (zero on error).
*/
{
/* Read superblock. */
readblock(1, scratch, 1024);
memcpy(&super, scratch, sizeof(super));
printf("super: %lx\n", super.s_magic);
/* Is it really a MINIX file system ? */
if (super.s_magic == SUPER_V2 || super.s_magic == SUPER_V3) {
if(super.s_magic == SUPER_V2)
super.s_block_size = 1024;
*bs = block_size = super.s_block_size;
printf("max_size: %d zones: %d imap_blocks: %d zones: %d\n",
super.s_max_size, super.s_imap_blocks,
super.s_zmap_blocks, super.s_nzones);
if(block_size < MIN_BLOCK_SIZE ||
block_size > RAWFS_MAX_BLOCK_SIZE) {
printf("bogus block size %d\n", block_size);
return 0;
}
nr_dzones= V2_NR_DZONES;
nr_indirects= V2_INDIRECTS(block_size);
inodes_per_block= V2_INODES_PER_BLOCK(block_size);
printf("v2/v3 %d ok\n", block_size);
printf("ipb %d\n", inodes_per_block);
return (off_t) super.s_zones << zone_shift;
} else
if (super.s_magic == SUPER_V1) {
*bs = block_size = 1024;
nr_dzones= V1_NR_DZONES;
nr_indirects= V1_INDIRECTS;
inodes_per_block= V1_INODES_PER_BLOCK;
printf("v1 ok\n");
return (off_t) super.s_nzones << zone_shift;
} else {
/* Filesystem not recognized as Minix. */
printf("not minix\n");
return 0;
}
}
void r_stat(Ino_t inum, struct stat *stp)
/* Return information about a file like stat(2) and remember it. */
{
block_t block;
block_t ino_block;
ino_t ino_offset;
/* Calculate start of i-list */
block = START_BLOCK + super.s_imap_blocks + super.s_zmap_blocks;
printf("r_stat: start of i-list: %d (ipb %d)\n",
block, inodes_per_block);
/* Calculate block with inode inum */
ino_block = ((inum - 1) / inodes_per_block);
ino_offset = ((inum - 1) % inodes_per_block);
block += ino_block;
printf("r_stat: block with inode: %d - readblock %d..\n", block, block_size);
/* Fetch the block */
readblock(block, scratch, block_size);
printf("r_stat: readblock done..\n", block);
if (super.s_magic == SUPER_V2 || super.s_magic == SUPER_V3) {
d2_inode *dip;
int i;
dip= &fsbuf(scratch).b_v2_ino[ino_offset];
curfil.i_mode= dip->d2_mode;
curfil.i_nlinks= dip->d2_nlinks;
curfil.i_uid= dip->d2_uid;
curfil.i_gid= dip->d2_gid;
curfil.i_size= dip->d2_size;
curfil.i_atime= dip->d2_atime;
curfil.i_mtime= dip->d2_mtime;
curfil.i_ctime= dip->d2_ctime;
for (i= 0; i < V2_NR_TZONES; i++)
curfil.i_zone[i]= dip->d2_zone[i];
} else {
d1_inode *dip;
int i;
dip= &fsbuf(scratch).b_v1_ino[ino_offset];
curfil.i_mode= dip->d1_mode;
curfil.i_nlinks= dip->d1_nlinks;
curfil.i_uid= dip->d1_uid;
curfil.i_gid= dip->d1_gid;
curfil.i_size= dip->d1_size;
curfil.i_atime= dip->d1_mtime;
curfil.i_mtime= dip->d1_mtime;
curfil.i_ctime= dip->d1_mtime;
for (i= 0; i < V1_NR_TZONES; i++)
curfil.i_zone[i]= dip->d1_zone[i];
}
curfil.i_dev= -1; /* Can't fill this in alas. */
curfil.i_num= inum;
stp->st_dev= curfil.i_dev;
stp->st_ino= curfil.i_num;
stp->st_mode= curfil.i_mode;
stp->st_nlink= curfil.i_nlinks;
stp->st_uid= curfil.i_uid;
stp->st_gid= curfil.i_gid;
stp->st_rdev= (dev_t) curfil.i_zone[0];
stp->st_size= curfil.i_size;
stp->st_atime= curfil.i_atime;
stp->st_mtime= curfil.i_mtime;
stp->st_ctime= curfil.i_ctime;
a_indir= a_dindir= 0;
dirpos= 0;
}
ino_t r_readdir(char *name)
/* Read next directory entry at "dirpos" from file "curfil". */
{
ino_t inum= 0;
int blkpos;
struct direct *dp;
if (!S_ISDIR(curfil.i_mode)) { errno= ENOTDIR; return -1; }
if(!block_size) { errno = 0; return -1; }
while (inum == 0 && dirpos < curfil.i_size) {
if ((blkpos= (int) (dirpos % block_size)) == 0) {
/* Need to fetch a new directory block. */
readblock(r_vir2abs(dirpos / block_size), dirbuf, block_size);
}
#ifdef FLEX
if (super.s_flags & S_FLEX) {
struct _fl_direct *dp;
dp= (struct _fl_direct *) (dirbuf + blkpos);
if ((inum= dp->d_ino) != 0) strcpy(name, dp->d_name);
dirpos+= (1 + dp->d_extent) * FL_DIR_ENTRY_SIZE;
continue;
}
#endif
/* Let dp point to the next entry. */
dp= (struct direct *) (dirbuf + blkpos);
if ((inum= dp->d_ino) != 0) {
/* This entry is occupied, return name. */
strncpy(name, dp->d_name, sizeof(dp->d_name));
name[sizeof(dp->d_name)]= 0;
}
dirpos+= DIR_ENTRY_SIZE;
}
return inum;
}
off_t r_vir2abs(off_t virblk)
/* Translate a block number in a file to an absolute disk block number.
* Returns 0 for a hole and -1 if block is past end of file.
*/
{
block_t b= virblk;
zone_t zone, ind_zone;
block_t z, zone_index;
int i;
if(!block_size) return -1;
/* Check if virblk within file. */
if (virblk * block_size >= curfil.i_size) return -1;
/* Calculate zone in which the datablock number is contained */
zone = (zone_t) (b >> zone_shift);
/* Calculate index of the block number in the zone */
zone_index = b - ((block_t) zone << zone_shift);
/* Go get the zone */
if (zone < (zone_t) nr_dzones) { /* direct block */
zone = curfil.i_zone[(int) zone];
z = ((block_t) zone << zone_shift) + zone_index;
return z;
}
/* The zone is not a direct one */
zone -= (zone_t) nr_dzones;
/* Is it single indirect ? */
if (zone < (zone_t) nr_indirects) { /* single indirect block */
ind_zone = curfil.i_zone[nr_dzones];
} else { /* double indirect block */
/* Fetch the double indirect block */
if ((ind_zone = curfil.i_zone[nr_dzones + 1]) == 0) return 0;
z = (block_t) ind_zone << zone_shift;
if (a_dindir != z) {
readblock(z, dindir, block_size);
a_dindir= z;
}
/* Extract the indirect zone number from it */
zone -= (zone_t) nr_indirects;
i = zone / (zone_t) nr_indirects;
ind_zone = (super.s_magic == SUPER_V2 || super.s_magic == SUPER_V3)
? fsbuf(dindir).b_v2_ind[i]
: fsbuf(dindir).b_v1_ind[i];
zone %= (zone_t) nr_indirects;
}
if (ind_zone == 0) return 0;
/* Extract the datablock number from the indirect zone */
z = (block_t) ind_zone << zone_shift;
if (a_indir != z) {
readblock(z, indir, block_size);
a_indir= z;
}
zone = (super.s_magic == SUPER_V2 || super.s_magic == SUPER_V3)
? fsbuf(indir).b_v2_ind[(int) zone]
: fsbuf(indir).b_v1_ind[(int) zone];
/* Calculate absolute datablock number */
z = ((block_t) zone << zone_shift) + zone_index;
return z;
}
ino_t r_lookup(Ino_t cwd, char *path)
/* Translates a pathname to an inode number. This is just a nice utility
* function, it only needs r_stat and r_readdir.
*/
{
char name[NAME_MAX+1], r_name[NAME_MAX+1];
char *n;
struct stat st;
ino_t ino;
ino= path[0] == '/' ? ROOT_INO : cwd;
for (;;) {
printf("ino %d..\n", ino);
if (ino == 0) {
errno= ENOENT;
return 0;
}
while (*path == '/') path++;
if (*path == 0) return ino;
printf("r_stat..\n");
r_stat(ino, &st);
printf("r_stat done..\n");
if (!S_ISDIR(st.st_mode)) {
errno= ENOTDIR;
return 0;
}
n= name;
while (*path != 0 && *path != '/')
if (n < name + NAME_MAX) *n++ = *path++;
*n= 0;
printf("r_readdir..\n");
while ((ino= r_readdir(r_name)) != 0
&& strcmp(name, r_name) != 0) {
printf("r_readdir %s isn't it..\n", r_name);
}
printf("after readdir loop: %s %s\n", name, r_name);
}
}
/*
* $PchId: rawfs.c,v 1.8 1999/11/05 23:14:15 philip Exp $
*/

43
boot/rawfs.h Executable file
View file

@ -0,0 +1,43 @@
/* rawfs.h - Raw Minix file system support. Author: Kees J. Bot
*
* off_t r_super(int *block_size);
* Initialize variables, returns the size of a valid Minix
* file system blocks, but zero on error.
*
* void r_stat(ino_t file, struct stat *stp);
* Return information about a file like stat(2) and
* remembers file for the next two calls.
*
* off_t r_vir2abs(off_t virblockno);
* Translate virtual block number in file to absolute
* disk block number. Returns 0 if the file contains
* a hole, or -1 if the block lies past the end of file.
*
* ino_t r_readdir(char *name);
* Return next directory entry or 0 if there are no more.
* Returns -1 and sets errno on error.
*
* ino_t r_lookup(ino_t cwd, char *path);
* A utility function that translates a pathname to an
* inode number. It starts from directory "cwd" unless
* path starts with a '/', then from ROOT_INO.
* Returns 0 and sets errno on error.
*
* One function needs to be provided by the outside world:
*
* void readblock(off_t blockno, char *buf, int block_size);
* Read a block into the buffer. Outside world handles
* errors.
*/
#define ROOT_INO ((ino_t) 1) /* Inode nr of root dir. */
off_t r_super(int *);
void r_stat(Ino_t file, struct stat *stp);
off_t r_vir2abs(off_t virblockno);
ino_t r_readdir(char *name);
ino_t r_lookup(Ino_t cwd, char *path);
/*
* $PchId: rawfs.h,v 1.4 1996/04/19 08:16:36 philip Exp $
*/

47
commands/Makefile Executable file
View file

@ -0,0 +1,47 @@
# Makefile for commands.
MAKE = exec make -$(MAKEFLAGS)
usage:
@echo "Usage: make all # Compile all commands" >&2
@echo " make install # Install the result (run as bin!)" >&2
@echo " make clean # Delete .o files and other junk" >&2
@false
all install clean:
cd `arch` && $(MAKE) $@
cd aal && $(MAKE) $@
cd advent && $(MAKE) $@
cd ash && $(MAKE) $@
cd autil && $(MAKE) $@
cd awk && $(MAKE) $@
cd bc && $(MAKE) $@
cd byacc && $(MAKE) $@
cd cawf && $(MAKE) $@
cd cron && $(MAKE) $@
cd de && $(MAKE) $@
cd dhcpd && $(MAKE) $@
cd dis88 && $(MAKE) $@
cd elle && $(MAKE) $@
cd elvis && $(MAKE) $@
cd flex-2.3.7 && $(MAKE) $@
cd ftp && $(MAKE) $@
cd ftpd && $(MAKE) $@
cd ibm && $(MAKE) $@
cd kermit && $(MAKE) $@
cd m4 && $(MAKE) $@
cd make && $(MAKE) $@
cd mined && $(MAKE) $@
cd patch && $(MAKE) $@
cd reboot && $(MAKE) $@
cd rlogind && $(MAKE) $@
cd scripts && $(MAKE) $@
cd sh && $(MAKE) $@
cd simple && $(MAKE) $@
cd talk && $(MAKE) $@
cd talkd && $(MAKE) $@
cd telnet && $(MAKE) $@
cd telnetd && $(MAKE) $@
cd urlget && $(MAKE) $@
cd yap && $(MAKE) $@
cd zmodem && $(MAKE) $@

56
commands/aal/Makefile Executable file
View file

@ -0,0 +1,56 @@
# Makefile for aal
CC=exec cc
CFLAGS=-I. -wo -DAAL -DSTB -DNDEBUG -DDISTRIBUTION -D_POSIX_SOURCE -D_MINIX
LDFLAGS=-i
all: aal
OFILES= archiver.o \
print.o \
rd.o \
rd_arhdr.o \
rd_unsig2.o \
sprint.o \
wr_arhdr.o \
wr_bytes.o \
wr_int2.o \
wr_long.o \
wr_ranlib.o \
format.o \
rd_bytes.o \
system.o \
write.o \
long2str.o
aal: $(OFILES)
$(CC) $(LDFLAGS) -o aal $(OFILES)
install -S 64k $@
install: /usr/bin/aal /usr/bin/ar
/usr/bin/aal: aal
install -cs -o bin aal $@
/usr/bin/ar: /usr/bin/aal
install -l $? $@
archiver.o:
print.o:
rd.o:
rd_arhdr.o:
rd_unsig2.o:
sprint.o:
wr_arhdr.o:
wr_bytes.o:
wr_int2.o:
wr_long.o:
wr_ranlib.o:
format.o:
rd_bytes.o:
system.o:
write.o:
long2str.o:
clean:
rm -f *.o core *.bak aal

25
commands/aal/arch.h Executable file
View file

@ -0,0 +1,25 @@
/* $Header$ */
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
#ifndef __ARCH_H_INCLUDED
#define __ARCH_H_INCLUDED
#define ARMAG 0177545
#define AALMAG 0177454
struct ar_hdr {
char ar_name[14];
long ar_date;
char ar_uid;
char ar_gid;
short ar_mode;
long ar_size;
};
#define AR_TOTAL 26
#define AR_SIZE 22
#endif /* __ARCH_H_INCLUDED */

800
commands/aal/archiver.c Executable file
View file

@ -0,0 +1,800 @@
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
/* ar - archiver Author: Michiel Huisjes */
/* Made into arch/aal by Ceriel Jacobs
*/
static char RcsId[] = "$Header$";
/*
* Usage: [arch|aal] [adprtvx] archive [file] ...
* v: verbose
* x: extract
* a: append
* r: replace (append when not in archive)
* d: delete
* t: print contents of archive
* p: print named files
* l: temporaries in current directory instead of /usr/tmp
* c: don't give "create" message
* u: replace only if dated later than member in archive
#ifdef DISTRIBUTION
* D: make distribution: use distr_time, uid=2, gid=2, mode=0644
#endif
*/
#include <sys/types.h>
#include <sys/stat.h>
#ifndef S_IREAD
#define S_IREAD S_IRUSR
#endif
#ifndef S_IWRITE
#define S_IWRITE S_IWUSR
#endif
#ifndef S_IEXEC
#define S_IEXEC S_IXUSR
#endif
#include <signal.h>
#include <arch.h>
#ifdef AAL
#include <ranlib.h>
#include <out.h>
#define MAGIC_NUMBER AALMAG
long offset;
struct ranlib *tab;
unsigned int tnum = 0;
char *tstrtab;
unsigned int tssiz = 0;
char *malloc(), *realloc(), *strcpy(), *strncpy();
long time();
unsigned int tabsz, strtabsz;
#else
#define MAGIC_NUMBER ARMAG
#endif
long lseek();
#define odd(nr) (nr & 01)
#define even(nr) (odd(nr) ? nr + 1 : nr)
typedef char BOOL;
#define FALSE 0
#define TRUE 1
#define READ 0
#define APPEND 2
#define CREATE 1
#define MEMBER struct ar_hdr
#define NIL_PTR ((char *) 0)
#define NIL_MEM ((MEMBER *) 0)
#define NIL_LONG ((long *) 0)
#define IO_SIZE (10 * 1024)
#define equal(str1, str2) (!strncmp((str1), (str2), 14))
#ifndef S_ISDIR
#define S_ISDIR(m) (m & S_IFDIR) /* is a directory */
#endif
BOOL verbose;
BOOL app_fl;
BOOL ex_fl;
BOOL show_fl;
BOOL pr_fl;
BOOL rep_fl;
BOOL del_fl;
BOOL nocr_fl;
BOOL local_fl;
BOOL update_fl;
#ifdef DISTRIBUTION
BOOL distr_fl;
long distr_time;
#endif
int ar_fd;
char io_buffer[IO_SIZE];
char *progname;
char temp_buf[32];
char *temp_arch = &temp_buf[0];
extern char *mktemp();
extern char *ctime();
usage()
{
error(TRUE, "usage: %s %s archive [file] ...\n",
progname,
#ifdef AAL
"[acdrtxvlu]"
#else
"[acdprtxvlu]"
#endif
);
}
/*VARARGS2*/
error(quit, str1, str2, str3, str4)
BOOL quit;
char *str1, *str2, *str3, *str4;
{
char errbuf[256];
sprint(errbuf, str1, str2, str3, str4);
write(2, errbuf, strlen(errbuf));
if (quit) {
unlink(temp_arch);
_exit(1);
}
}
char *basename(path)
char *path;
{
register char *ptr = path;
register char *last = NIL_PTR;
while (*ptr != '\0') {
if (*ptr == '/')
last = ptr;
ptr++;
}
if (last == NIL_PTR)
return path;
if (*(last + 1) == '\0') {
*last = '\0';
return basename(path);
}
return last + 1;
}
extern unsigned int rd_unsigned2();
open_archive(name, mode)
register char *name;
register int mode;
{
unsigned short magic = 0;
int fd;
if (mode == CREATE) {
if ((fd = creat(name, 0666)) < 0)
error(TRUE, "cannot creat %s\n", name);
magic = MAGIC_NUMBER;
wr_int2(fd, magic);
return fd;
}
if ((fd = open(name, mode)) < 0) {
if (mode == APPEND) {
close(open_archive(name, CREATE));
if (!nocr_fl) error(FALSE, "%s: creating %s\n", progname, name);
return open_archive(name, APPEND);
}
error(TRUE, "cannot open %s\n", name);
}
lseek(fd, 0L, 0);
magic = rd_unsigned2(fd);
if (magic != AALMAG && magic != ARMAG)
error(TRUE, "%s is not in ar format\n", name);
return fd;
}
#if __STDC__
void catch(int sig)
#else
catch()
#endif
{
unlink(temp_arch);
_exit (2);
}
main(argc, argv)
int argc;
char *argv[];
{
register char *ptr;
int needs_arg = 0;
progname = argv[0];
if (argc < 3)
usage();
for (ptr = argv[1]; *ptr; ptr++) {
switch (*ptr) {
case 't' :
show_fl = TRUE;
break;
case 'v' :
verbose = TRUE;
break;
case 'x' :
ex_fl = TRUE;
break;
case 'a' :
needs_arg = 1;
app_fl = TRUE;
break;
case 'c' :
nocr_fl = TRUE;
break;
#ifndef AAL
case 'p' :
needs_arg = 1;
pr_fl = TRUE;
break;
#endif
case 'd' :
needs_arg = 1;
del_fl = TRUE;
break;
case 'r' :
needs_arg = 1;
rep_fl = TRUE;
break;
case 'l' :
local_fl = TRUE;
break;
case 'u' :
update_fl = TRUE;
break;
#ifdef DISTRIBUTION
case 'D' :
distr_fl = TRUE;
break;
#endif
default :
usage();
}
}
if (needs_arg && argc <= 3)
usage();
#ifdef DISTRIBUTION
if (distr_fl) {
struct stat statbuf;
stat(progname, &statbuf);
distr_time = statbuf.st_mtime;
}
#endif
if (local_fl) strcpy(temp_arch, "ar.XXXXXX");
else strcpy(temp_arch, "/usr/tmp/ar.XXXXXX");
if (app_fl + ex_fl + del_fl + rep_fl + show_fl + pr_fl != 1)
usage();
if (update_fl && !rep_fl)
usage();
if (rep_fl || del_fl
#ifdef AAL
|| app_fl
#endif
) {
mktemp(temp_arch);
}
#ifdef AAL
tab = (struct ranlib *) malloc(512 * sizeof(struct ranlib));
tstrtab = malloc(4096);
if (!tab || !tstrtab) error(TRUE,"Out of core\n");
tabsz = 512;
strtabsz = 4096;
#endif
signal(SIGINT, catch);
get(argc, argv);
return 0;
}
MEMBER *
get_member()
{
static MEMBER member;
again:
if (rd_arhdr(ar_fd, &member) == 0)
return NIL_MEM;
if (member.ar_size < 0) {
error(TRUE, "archive has member with negative size\n");
}
#ifdef AAL
if (equal(SYMDEF, member.ar_name)) {
lseek(ar_fd, member.ar_size, 1);
goto again;
}
#endif
return &member;
}
char *get_mode();
get(argc, argv)
int argc;
register char *argv[];
{
register MEMBER *member;
int i = 0;
int temp_fd, read_chars;
ar_fd = open_archive(argv[2], (show_fl || pr_fl || ex_fl) ? READ : APPEND);
if (rep_fl || del_fl
#ifdef AAL
|| app_fl
#endif
)
temp_fd = open_archive(temp_arch, CREATE);
while ((member = get_member()) != NIL_MEM) {
if (argc > 3) {
for (i = 3; i < argc; i++) {
if (equal(basename(argv[i]), member->ar_name))
break;
}
if (i == argc || app_fl) {
if (rep_fl || del_fl
#ifdef AAL
|| app_fl
#endif
) {
#ifdef AAL
if (i != argc) {
print("%s: already in archive\n", argv[i]);
argv[i] = "";
}
#endif
wr_arhdr(temp_fd, member);
copy_member(member, ar_fd, temp_fd, 0);
}
else {
#ifndef AAL
if (app_fl && i != argc) {
print("%s: already in archive\n", argv[i]);
argv[i] = "";
}
#endif
lseek(ar_fd, even(member->ar_size),1);
}
continue;
}
}
if (ex_fl || pr_fl)
extract(member);
else {
if (rep_fl) {
int isold = 0;
if(update_fl) {
struct stat status;
if (stat(argv[i], &status) >= 0) {
if(status.st_mtime <= member->ar_date)
isold = 1;
}
}
if(!isold)
add(argv[i], temp_fd, "r - %s\n");
else {
wr_arhdr(temp_fd, member);
copy_member(member, ar_fd, temp_fd, 0);
if(verbose)
show("r - %s (old)\n", member->ar_name);
}
}
else if (show_fl) {
char buf[sizeof(member->ar_name) + 2];
register char *p = buf, *q = member->ar_name;
while (q <= &member->ar_name[sizeof(member->ar_name)-1] && *q) {
*p++ = *q++;
}
*p++ = '\n';
*p = '\0';
if (verbose) {
char *mode = get_mode(member->ar_mode);
char *date = ctime(&(member->ar_date));
*(date + 16) = '\0';
*(date + 24) = '\0';
print("%s%3u/%u%7ld %s %s %s",
mode,
(unsigned) (member->ar_uid & 0377),
(unsigned) (member->ar_gid & 0377),
member->ar_size,
date+4,
date+20,
buf);
}
else print(buf);
}
else if (del_fl)
show("d - %s\n", member->ar_name);
lseek(ar_fd, even(member->ar_size), 1);
}
argv[i] = "";
}
if (argc > 3) {
for (i = 3; i < argc; i++)
if (argv[i][0] != '\0') {
#ifndef AAL
if (app_fl)
add(argv[i], ar_fd, "a - %s\n");
else
#endif
if (rep_fl
#ifdef AAL
|| app_fl
#endif
)
add(argv[i], temp_fd, "a - %s\n");
else {
print("%s: not found\n", argv[i]);
}
}
}
if (rep_fl || del_fl
#ifdef AAL
|| app_fl
#endif
) {
signal(SIGINT, SIG_IGN);
close(ar_fd);
close(temp_fd);
ar_fd = open_archive(argv[2], CREATE);
temp_fd = open_archive(temp_arch, APPEND);
#ifdef AAL
write_symdef();
#endif
while ((read_chars = read(temp_fd, io_buffer, IO_SIZE)) > 0)
mwrite(ar_fd, io_buffer, read_chars);
close(temp_fd);
unlink(temp_arch);
}
close(ar_fd);
}
add(name, fd, mess)
char *name;
int fd;
char *mess;
{
static MEMBER member;
register int read_chars;
struct stat status;
int src_fd;
if (stat(name, &status) < 0) {
error(FALSE, "cannot find %s\n", name);
return;
}
else if (S_ISDIR(status.st_mode)) {
error(FALSE, "%s is a directory (ignored)\n", name);
return;
}
else if ((src_fd = open(name, 0)) < 0) {
error(FALSE, "cannot open %s\n", name);
return;
}
strncpy (member.ar_name, basename (name), sizeof(member.ar_name));
member.ar_uid = status.st_uid;
member.ar_gid = status.st_gid;
member.ar_mode = status.st_mode;
member.ar_date = status.st_mtime;
member.ar_size = status.st_size;
#ifdef DISTRIBUTION
if (distr_fl) {
member.ar_uid = 2;
member.ar_gid = 2;
member.ar_mode = 0644;
member.ar_date = distr_time;
}
#endif
wr_arhdr(fd, &member);
#ifdef AAL
do_object(src_fd, member.ar_size);
lseek(src_fd, 0L, 0);
offset += AR_TOTAL + even(member.ar_size);
#endif
while (status.st_size > 0) {
int x = IO_SIZE;
read_chars = x;
if (status.st_size < x) {
x = status.st_size;
read_chars = x;
status.st_size = 0;
x = even(x);
}
else status.st_size -= x;
if (read(src_fd, io_buffer, read_chars) != read_chars) {
error(FALSE,"%s seems to shrink\n", name);
break;
}
mwrite(fd, io_buffer, x);
}
if (verbose)
show(mess, member.ar_name);
close(src_fd);
}
extract(member)
register MEMBER *member;
{
int fd = 1;
char buf[sizeof(member->ar_name) + 1];
strncpy(buf, member->ar_name, sizeof(member->ar_name));
buf[sizeof(member->ar_name)] = 0;
if (pr_fl == FALSE && (fd = creat(buf, 0666)) < 0) {
error(FALSE, "cannot create %s\n", buf);
fd = -1;
}
if (verbose) {
if (pr_fl == FALSE) show("x - %s\n", buf);
else show("\n<%s>\n\n", buf);
}
copy_member(member, ar_fd, fd, 1);
if (fd >= 0 && fd != 1)
close(fd);
if (pr_fl == FALSE) chmod(buf, member->ar_mode);
}
copy_member(member, from, to, extracting)
register MEMBER *member;
int from, to;
{
register int rest;
long mem_size = member->ar_size;
BOOL is_odd = odd(mem_size) ? TRUE : FALSE;
#ifdef AAL
if (! extracting) {
long pos = lseek(from, 0L, 1);
do_object(from, mem_size);
offset += AR_TOTAL + even(mem_size);
lseek(from, pos, 0);
}
#endif
do {
rest = mem_size > (long) IO_SIZE ? IO_SIZE : (int) mem_size;
if (read(from, io_buffer, rest) != rest) {
char buf[sizeof(member->ar_name) + 1];
strncpy(buf, member->ar_name, sizeof(member->ar_name));
buf[sizeof(member->ar_name)] = 0;
error(TRUE, "read error on %s\n", buf);
}
if (to >= 0) mwrite(to, io_buffer, rest);
mem_size -= (long) rest;
} while (mem_size > 0L);
if (is_odd) {
lseek(from, 1L, 1);
if (to >= 0 && ! extracting)
lseek(to, 1L, 1);
}
}
char *
get_mode(mode)
register int mode;
{
static char mode_buf[11];
register int tmp = mode;
int i;
mode_buf[9] = ' ';
for (i = 0; i < 3; i++) {
mode_buf[i * 3] = (tmp & S_IREAD) ? 'r' : '-';
mode_buf[i * 3 + 1] = (tmp & S_IWRITE) ? 'w' : '-';
mode_buf[i * 3 + 2] = (tmp & S_IEXEC) ? 'x' : '-';
tmp <<= 3;
}
if (mode & S_ISUID)
mode_buf[2] = 's';
if (mode & S_ISGID)
mode_buf[5] = 's';
return mode_buf;
}
wr_fatal()
{
error(TRUE, "write error\n");
}
rd_fatal()
{
error(TRUE, "read error\n");
}
mwrite(fd, address, bytes)
int fd;
register char *address;
register int bytes;
{
if (write(fd, address, bytes) != bytes)
error(TRUE, "write error\n");
}
show(s, name)
char *s, *name;
{
MEMBER x;
char buf[sizeof(x.ar_name)+1];
register char *p = buf, *q = name;
while (q <= &name[sizeof(x.ar_name)-1] && *q) *p++ = *q++;
*p++ = '\0';
print(s, buf);
}
#ifdef AAL
/*
* Write out the ranlib table: first 4 bytes telling how many ranlib structs
* there are, followed by the ranlib structs,
* then 4 bytes giving the size of the string table, followed by the string
* table itself.
*/
write_symdef()
{
register struct ranlib *ran;
register int i;
register long delta;
MEMBER arbuf;
if (odd(tssiz))
tstrtab[tssiz++] = '\0';
for (i = 0; i < sizeof(arbuf.ar_name); i++)
arbuf.ar_name[i] = '\0';
strcpy(arbuf.ar_name, SYMDEF);
arbuf.ar_size = 4 + 2 * 4 * (long)tnum + 4 + (long)tssiz;
time(&arbuf.ar_date);
arbuf.ar_uid = getuid();
arbuf.ar_gid = getgid();
arbuf.ar_mode = 0444;
#ifdef DISTRIBUTION
if (distr_fl) {
arbuf.ar_uid = 2;
arbuf.ar_gid = 2;
arbuf.ar_date = distr_time;
}
#endif
wr_arhdr(ar_fd,&arbuf);
wr_long(ar_fd, (long) tnum);
/*
* Account for the space occupied by the magic number
* and the ranlib table.
*/
delta = 2 + AR_TOTAL + arbuf.ar_size;
for (ran = tab; ran < &tab[tnum]; ran++) {
ran->ran_pos += delta;
}
wr_ranlib(ar_fd, tab, (long) tnum);
wr_long(ar_fd, (long) tssiz);
wr_bytes(ar_fd, tstrtab, (long) tssiz);
}
/*
* Return whether the bytes in `buf' form a good object header.
* The header is put in `headp'.
*/
int
is_outhead(headp)
register struct outhead *headp;
{
return !BADMAGIC(*headp) && headp->oh_nname != 0;
}
do_object(f, size)
long size;
{
struct outhead headbuf;
if (size < SZ_HEAD) {
/* It can't be an object file. */
return;
}
/*
* Read a header to see if it is an object file.
*/
if (! rd_fdopen(f)) {
rd_fatal();
}
rd_ohead(&headbuf);
if (!is_outhead(&headbuf)) {
return;
}
do_names(&headbuf);
}
/*
* First skip the names and read in the string table, then seek back to the
* name table and read and write the names one by one. Update the ranlib table
* accordingly.
*/
do_names(headp)
struct outhead *headp;
{
register char *strings;
register int nnames = headp->oh_nname;
#define NNAMES 100
struct outname namebuf[NNAMES];
long xxx = OFF_CHAR(*headp);
if ( headp->oh_nchar != (unsigned int)headp->oh_nchar ||
(strings = malloc((unsigned int)headp->oh_nchar)) == (char *)0
) {
error(TRUE, "string table too big\n");
}
rd_string(strings, headp->oh_nchar);
while (nnames) {
int i = nnames >= NNAMES ? NNAMES : nnames;
register struct outname *p = namebuf;
nnames -= i;
rd_name(namebuf, i);
while (i--) {
long off = p->on_foff - xxx;
if (p->on_foff == (long)0) {
p++;
continue; /* An unrecognizable name. */
}
p->on_mptr = strings + off;
/*
* Only enter names that are exported and are really
* defined. Also enter common names. Note, that
* this might cause problems when the name is really
* defined in a later file, with a value != 0.
* However, this problem also exists on the Unix
* ranlib archives.
*/
if ( (p->on_type & S_EXT) &&
(p->on_type & S_TYP) != S_UND
)
enter_name(p);
p++;
}
}
free(strings);
}
enter_name(namep)
struct outname *namep;
{
register char *cp;
if (tnum >= tabsz) {
tab = (struct ranlib *)
realloc((char *) tab, (tabsz += 512) * sizeof(struct ranlib));
if (! tab) error(TRUE, "Out of core\n");
}
tab[tnum].ran_off = tssiz;
tab[tnum].ran_pos = offset;
for (cp = namep->on_mptr;; cp++) {
if (tssiz >= strtabsz) {
tstrtab = realloc(tstrtab, (strtabsz += 4096));
if (! tstrtab) error(TRUE, "string table overflow\n");
}
tstrtab[tssiz++] = *cp;
if (!*cp) break;
}
tnum++;
}
#endif AAL

9
commands/aal/byte_order.h Executable file
View file

@ -0,0 +1,9 @@
#if defined(mc68020) || defined(mc68000) || defined(sparc)
#define BYTES_REVERSED 1
#define WORDS_REVERSED 1
#define CHAR_UNSIGNED 0
#else
#define BYTES_REVERSED 0
#define WORDS_REVERSED 0
#define CHAR_UNSIGNED 0
#endif

112
commands/aal/format.c Executable file
View file

@ -0,0 +1,112 @@
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
/* $Header$ */
#if __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
extern char *long2str();
static int
integral(c)
{
switch (c) {
case 'b':
return -2;
case 'd':
return 10;
case 'o':
return -8;
case 'u':
return -10;
case 'x':
return -16;
}
return 0;
}
/*VARARGS2*/
/*FORMAT1 $
%s = char *
%l = long
%c = int
%[uxbo] = unsigned int
%d = int
$ */
int
_format(buf, fmt, argp)
char *buf, *fmt;
register va_list argp;
{
register char *pf = fmt;
register char *pb = buf;
while (*pf) {
if (*pf == '%') {
register width, base, pad, npad;
char *arg;
char cbuf[2];
char *badformat = "<bad format>";
/* get padder */
if (*++pf == '0') {
pad = '0';
++pf;
}
else
pad = ' ';
/* get width */
width = 0;
while (*pf >= '0' && *pf <= '9')
width = 10 * width + *pf++ - '0';
if (*pf == 's') {
arg = va_arg(argp, char *);
}
else
if (*pf == 'c') {
cbuf[0] = va_arg(argp, int);
cbuf[1] = '\0';
arg = &cbuf[0];
}
else
if (*pf == 'l') {
/* alignment ??? */
if (base = integral(*++pf)) {
arg = long2str(va_arg(argp,long), base);
}
else {
pf--;
arg = badformat;
}
}
else
if (base = integral(*pf)) {
arg = long2str((long)va_arg(argp,int), base);
}
else
if (*pf == '%')
arg = "%";
else
arg = badformat;
npad = width - strlen(arg);
while (npad-- > 0)
*pb++ = pad;
while (*pb++ = *arg++);
pb--;
pf++;
}
else
*pb++ = *pf++;
}
return pb - buf;
}

19
commands/aal/local.h Executable file
View file

@ -0,0 +1,19 @@
/* $Header$ */
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
/* collection of options, selected by including or excluding 'defines' */
/* Version number of the EM object code */
# define VERSION 3 /* 16 bits number */
/* The default machine used by ack, acc, apc */
# define ACKM "minix"
/* size of local machine, either 0 (for 16 bit address space), or 1 */
# undef BIGMACHINE 1
/* operating system, SYS_5, V7, BSD4_1 or BSD4_2; Do NOT delete the comment
in the next line! */
# define V7 1 /* SYSTEM */

67
commands/aal/long2str.c Executable file
View file

@ -0,0 +1,67 @@
/* $Header$ */
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
/* Integer to String translator
-> base is a value from [-16,-2] V [2,16]
-> base < 0: see 'val' as unsigned value
-> no checks for buffer overflow and illegal parameters
(1985, EHB)
*/
#define MAXWIDTH 32
char *
long2str(val, base)
register long val;
register base;
{
static char numbuf[MAXWIDTH];
static char vec[] = "0123456789ABCDEF";
register char *p = &numbuf[MAXWIDTH];
int sign = (base > 0);
*--p = '\0'; /* null-terminate string */
if (val) {
if (base > 0) {
if (val < 0L) {
long v1 = -val;
if (v1 == val)
goto overflow;
val = v1;
}
else
sign = 0;
}
else
if (base < 0) { /* unsigned */
base = -base;
if (val < 0L) { /* taken from Amoeba src */
register mod, i;
overflow:
mod = 0;
for (i = 0; i < 8 * sizeof val; i++) {
mod <<= 1;
if (val < 0)
mod++;
val <<= 1;
if (mod >= base) {
mod -= base;
val++;
}
}
*--p = vec[mod];
}
}
do {
*--p = vec[(int) (val % base)];
val /= base;
} while (val != 0L);
if (sign)
*--p = '-'; /* don't forget it !! */
}
else
*--p = '0'; /* just a simple 0 */
return p;
}

76
commands/aal/object.h Executable file
View file

@ -0,0 +1,76 @@
/* $Header$ */
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
#include "byte_order.h"
#include <local.h>
#include <stdio.h>
#if CHAR_UNSIGNED
#define Xchar(ch) (ch)
#else
#define Xchar(ch) ((ch) & 0377)
#endif
#if ! defined(BYTES_REVERSED)
#define BYTES_REVERSED 1
#endif
#if ! defined(WORDS_REVERSED)
#define WORDS_REVERSED 1
#endif
#if BYTES_REVERSED
#define uget2(c) (Xchar((c)[0]) | ((unsigned) Xchar((c)[1]) << 8))
#define Xput2(i, c) (((c)[0] = (i)), ((c)[1] = (i) >> 8))
#define put2(i, c) { register int j = (i); Xput2(j, c); }
#else
#define uget2(c) (* ((unsigned short *) (c)))
#define Xput2(i, c) (* ((short *) (c)) = (i))
#define put2(i, c) Xput2(i, c)
#endif
#define get2(c) ((short) uget2(c))
#if WORDS_REVERSED || BYTES_REVERSED
#define get4(c) (uget2(c) | ((long) uget2((c)+2) << 16))
#define put4(l, c) { register long x=(l); \
Xput2((int)x,c); \
Xput2((int)(x>>16),(c)+2); \
}
#else
#define get4(c) (* ((long *) (c)))
#define put4(l, c) (* ((long *) (c)) = (l))
#endif
#define SECTCNT 3 /* number of sections with own output buffer */
#if BIGMACHINE
#define WBUFSIZ (8*BUFSIZ)
#else
#define WBUFSIZ BUFSIZ
#endif
struct fil {
int cnt;
char *pnow;
char *pbegin;
long currpos;
int fd;
char pbuf[WBUFSIZ];
};
extern struct fil __parts[];
#define PARTEMIT 0
#define PARTRELO (PARTEMIT+SECTCNT)
#define PARTNAME (PARTRELO+1)
#define PARTCHAR (PARTNAME+1)
#ifdef SYMDBUG
#define PARTDBUG (PARTCHAR+1)
#else
#define PARTDBUG (PARTCHAR+0)
#endif
#define NPARTS (PARTDBUG + 1)
#define getsect(s) (PARTEMIT+((s)>=(SECTCNT-1)?(SECTCNT-1):(s)))

126
commands/aal/out.h Executable file
View file

@ -0,0 +1,126 @@
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
/* $Header$ */
#ifndef __OUT_H_INCLUDED
#define __OUT_H_INCLUDED
/*
* output format for ACK assemblers
*/
#ifndef ushort
#define ushort unsigned short
#endif /* ushort */
struct outhead {
ushort oh_magic; /* magic number */
ushort oh_stamp; /* version stamp */
ushort oh_flags; /* several format flags */
ushort oh_nsect; /* number of outsect structures */
ushort oh_nrelo; /* number of outrelo structures */
ushort oh_nname; /* number of outname structures */
long oh_nemit; /* sum of all os_flen */
long oh_nchar; /* size of string area */
};
#define O_MAGIC 0x0201 /* magic number of output file */
#define O_STAMP 0 /* version stamp */
#define MAXSECT 64 /* Maximum number of sections */
#define HF_LINK 0x0004 /* unresolved references left */
#define HF_8086 0x0008 /* os_base specially encoded */
struct outsect {
long os_base; /* startaddress in machine */
long os_size; /* section size in machine */
long os_foff; /* startaddress in file */
long os_flen; /* section size in file */
long os_lign; /* section alignment */
};
struct outrelo {
char or_type; /* type of reference */
char or_sect; /* referencing section */
ushort or_nami; /* referenced symbol index */
long or_addr; /* referencing address */
};
struct outname {
union {
char *on_ptr; /* symbol name (in core) */
long on_off; /* symbol name (in file) */
} on_u;
#define on_mptr on_u.on_ptr
#define on_foff on_u.on_off
ushort on_type; /* symbol type */
ushort on_desc; /* debug info */
long on_valu; /* symbol value */
};
/*
* relocation type bits
*/
#define RELSZ 0x07 /* relocation length */
#define RELO1 1 /* 1 byte */
#define RELO2 2 /* 2 bytes */
#define RELO4 4 /* 4 bytes */
#define RELPC 0x08 /* pc relative */
#define RELBR 0x10 /* High order byte lowest address. */
#define RELWR 0x20 /* High order word lowest address. */
/*
* section type bits and fields
*/
#define S_TYP 0x007F /* undefined, absolute or relative */
#define S_EXT 0x0080 /* external flag */
#define S_ETC 0x7F00 /* for symbolic debug, bypassing 'as' */
/*
* S_TYP field values
*/
#define S_UND 0x0000 /* undefined item */
#define S_ABS 0x0001 /* absolute item */
#define S_MIN 0x0002 /* first user section */
#define S_MAX (S_TYP-1) /* last user section */
#define S_CRS S_TYP /* on_valu is symbol index which contains value */
/*
* S_ETC field values
*/
#define S_SCT 0x0100 /* section names */
#define S_LIN 0x0200 /* hll source line item */
#define S_FIL 0x0300 /* hll source file item */
#define S_MOD 0x0400 /* ass source file item */
#define S_COM 0x1000 /* Common name. */
#define S_STB 0xe000 /* entries with any of these bits set are
reserved for debuggers
*/
/*
* structure format strings
*/
#define SF_HEAD "22222244"
#define SF_SECT "44444"
#define SF_RELO "1124"
#define SF_NAME "4224"
/*
* structure sizes (bytes in file; add digits in SF_*)
*/
#define SZ_HEAD 20
#define SZ_SECT 20
#define SZ_RELO 8
#define SZ_NAME 12
/*
* file access macros
*/
#define BADMAGIC(x) ((x).oh_magic!=O_MAGIC)
#define OFF_SECT(x) SZ_HEAD
#define OFF_EMIT(x) (OFF_SECT(x) + ((long)(x).oh_nsect * SZ_SECT))
#define OFF_RELO(x) (OFF_EMIT(x) + (x).oh_nemit)
#define OFF_NAME(x) (OFF_RELO(x) + ((long)(x).oh_nrelo * SZ_RELO))
#define OFF_CHAR(x) (OFF_NAME(x) + ((long)(x).oh_nname * SZ_NAME))
#endif /* __OUT_H_INCLUDED */

7
commands/aal/param.h Executable file
View file

@ -0,0 +1,7 @@
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
/* $Header$ */
#define SSIZE 1024

42
commands/aal/print.c Executable file
View file

@ -0,0 +1,42 @@
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
/* $Header$ */
#if __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#include <system.h>
#include "param.h"
/*VARARGS*/
/*FORMAT0v $
%s = char *
%l = long
%c = int
%[uxbo] = unsigned int
%d = int
$ */
int
#if __STDC__
print(char *fmt, ...)
#else
print(fmt, va_alist)
char *fmt;
va_dcl
#endif
{
va_list args;
char buf[SSIZE];
#if __STDC__
va_start(args, fmt);
#else
va_start(args);
#endif
sys_write(STDOUT, buf, _format(buf, fmt, args));
va_end(args);
}

34
commands/aal/ranlib.h Executable file
View file

@ -0,0 +1,34 @@
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
/* $Header$ */
#ifndef __RANLIB_H_INCLUDED
#define __RANLIB_H_INCLUDED
#ifndef SYMDEF
# define SYMDEF "__.SYMDEF"
#endif /* SYMDEF */
/*
* Structure of the SYMDEF table of contents for an archive.
* SYMDEF begins with a long giving the number of ranlib
* structures that immediately follow, and then continues with a string
* table consisting of a long giving the number of bytes of
* strings that follow and then the strings themselves.
*/
struct ranlib {
union {
char *ran__ptr; /* symbol name (in core) */
long ran__off; /* symbol name (in file) */
} ran_u;
#define ran_ptr ran_u.ran__ptr
#define ran_off ran_u.ran__off
long ran_pos; /* library member is at this position */
};
#define SZ_RAN 8
#define SF_RAN "44"
#endif /* __RANLIB_H_INCLUDED */

254
commands/aal/rd.c Executable file
View file

@ -0,0 +1,254 @@
/* $Header$ */
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
#include <out.h>
#include "object.h"
extern long lseek();
/*
* Parts of the output file.
*/
#undef PARTEMIT
#undef PARTRELO
#undef PARTNAME
#undef PARTCHAR
#undef PARTDBUG
#undef NPARTS
#define PARTEMIT 0
#define PARTRELO 1
#define PARTNAME 2
#define PARTCHAR 3
#ifdef SYMDBUG
#define PARTDBUG 4
#else
#define PARTDBUG 3
#endif
#define NPARTS (PARTDBUG + 1)
static long offset[MAXSECT];
static int outfile;
static long outseek[NPARTS];
static long currpos;
static long rd_base;
#define OUTSECT(i) \
(outseek[PARTEMIT] = offset[i])
#define BEGINSEEK(p, o) \
(outseek[(p)] = (o))
static int sectionnr;
static
OUTREAD(p, b, n)
char *b;
long n;
{
register long l = outseek[p];
if (currpos != l) {
lseek(outfile, l, 0);
}
rd_bytes(outfile, b, n);
l += n;
currpos = l;
outseek[p] = l;
}
/*
* Open the output file according to the chosen strategy.
*/
int
rd_open(f)
char *f;
{
if ((outfile = open(f, 0)) < 0)
return 0;
return rd_fdopen(outfile);
}
static int offcnt;
rd_fdopen(fd)
{
register int i;
for (i = 0; i < NPARTS; i++) outseek[i] = 0;
offcnt = 0;
rd_base = lseek(fd, 0L, 1);
if (rd_base < 0) {
return 0;
}
currpos = rd_base;
outseek[PARTEMIT] = currpos;
outfile = fd;
sectionnr = 0;
return 1;
}
rd_close()
{
close(outfile);
outfile = -1;
}
rd_fd()
{
return outfile;
}
rd_ohead(head)
register struct outhead *head;
{
register long off;
OUTREAD(PARTEMIT, (char *) head, (long) SZ_HEAD);
#if ! (BYTES_REVERSED || WORDS_REVERSED)
if (sizeof(struct outhead) != SZ_HEAD)
#endif
{
register char *c = (char *) head + (SZ_HEAD-4);
head->oh_nchar = get4(c);
c -= 4; head->oh_nemit = get4(c);
c -= 2; head->oh_nname = uget2(c);
c -= 2; head->oh_nrelo = uget2(c);
c -= 2; head->oh_nsect = uget2(c);
c -= 2; head->oh_flags = uget2(c);
c -= 2; head->oh_stamp = uget2(c);
c -= 2; head->oh_magic = uget2(c);
}
off = OFF_RELO(*head) + rd_base;
BEGINSEEK(PARTRELO, off);
off += (long) head->oh_nrelo * SZ_RELO;
BEGINSEEK(PARTNAME, off);
off += (long) head->oh_nname * SZ_NAME;
BEGINSEEK(PARTCHAR, off);
#ifdef SYMDBUG
off += head->oh_nchar;
BEGINSEEK(PARTDBUG, off);
#endif
}
rd_rew_relos(head)
register struct outhead *head;
{
register long off = OFF_RELO(*head) + rd_base;
BEGINSEEK(PARTRELO, off);
}
rd_sect(sect, cnt)
register struct outsect *sect;
register unsigned int cnt;
{
register char *c = (char *) sect + cnt * SZ_SECT;
OUTREAD(PARTEMIT, (char *) sect, (long)cnt * SZ_SECT);
sect += cnt;
offcnt += cnt;
while (cnt--) {
sect--;
#if ! (BYTES_REVERSED || WORDS_REVERSED)
if (sizeof(struct outsect) != SZ_SECT)
#endif
{
c -= 4; sect->os_lign = get4(c);
c -= 4; sect->os_flen = get4(c);
c -= 4; sect->os_foff = get4(c);
}
offset[--offcnt] = sect->os_foff + rd_base;
#if ! (BYTES_REVERSED || WORDS_REVERSED)
if (sizeof(struct outsect) != SZ_SECT)
#endif
{
c -= 4; sect->os_size = get4(c);
c -= 4; sect->os_base = get4(c);
}
}
}
rd_outsect(s)
{
OUTSECT(s);
sectionnr = s;
}
/*
* We don't have to worry about byte order here.
*/
rd_emit(emit, cnt)
char *emit;
long cnt;
{
OUTREAD(PARTEMIT, emit, cnt);
offset[sectionnr] += cnt;
}
rd_relo(relo, cnt)
register struct outrelo *relo;
register unsigned int cnt;
{
OUTREAD(PARTRELO, (char *) relo, (long) cnt * SZ_RELO);
#if ! (BYTES_REVERSED || WORDS_REVERSED)
if (sizeof(struct outrelo) != SZ_RELO)
#endif
{
register char *c = (char *) relo + (long) cnt * SZ_RELO;
relo += cnt;
while (cnt--) {
relo--;
c -= 4; relo->or_addr = get4(c);
c -= 2; relo->or_nami = uget2(c);
relo->or_sect = *--c;
relo->or_type = *--c;
}
}
}
rd_name(name, cnt)
register struct outname *name;
register unsigned int cnt;
{
OUTREAD(PARTNAME, (char *) name, (long) cnt * SZ_NAME);
#if ! (BYTES_REVERSED || WORDS_REVERSED)
if (sizeof(struct outname) != SZ_NAME)
#endif
{
register char *c = (char *) name + (long) cnt * SZ_NAME;
name += cnt;
while (cnt--) {
name--;
c -= 4; name->on_valu = get4(c);
c -= 2; name->on_desc = uget2(c);
c -= 2; name->on_type = uget2(c);
c -= 4; name->on_foff = get4(c);
}
}
}
rd_string(addr, len)
char *addr;
long len;
{
OUTREAD(PARTCHAR, addr, len);
}
#ifdef SYMDBUG
rd_dbug(buf, size)
char *buf;
long size;
{
OUTREAD(PARTDBUG, buf, size);
}
#endif

35
commands/aal/rd_arhdr.c Executable file
View file

@ -0,0 +1,35 @@
/* $Header$ */
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
#include <arch.h>
#include "object.h"
int
rd_arhdr(fd, arhdr)
register struct ar_hdr *arhdr;
{
char buf[AR_TOTAL];
register char *c = buf;
register char *p = arhdr->ar_name;
register int i;
i = read(fd, c, AR_TOTAL);
if (i == 0) return 0;
if (i != AR_TOTAL) {
rd_fatal();
}
i = 14;
while (i--) {
*p++ = *c++;
}
arhdr->ar_date = ((long) get2(c)) << 16; c += 2;
arhdr->ar_date |= ((long) get2(c)) & 0xffff; c += 2;
arhdr->ar_uid = *c++;
arhdr->ar_gid = *c++;
arhdr->ar_mode = get2(c); c += 2;
arhdr->ar_size = (long) get2(c) << 16; c += 2;
arhdr->ar_size |= (long) get2(c) & 0xffff;
return 1;
}

32
commands/aal/rd_bytes.c Executable file
View file

@ -0,0 +1,32 @@
/* $Header$ */
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
#define MININT (1 << (sizeof(int) * 8 - 1))
#define MAXCHUNK (~MININT) /* Highest count we read(2). */
/* Unfortunately, MAXCHUNK is too large with some compilers. Put it in
an int!
*/
static int maxchunk = MAXCHUNK;
/*
* We don't have to worry about byte order here.
* Just read "cnt" bytes from file-descriptor "fd".
*/
int
rd_bytes(fd, string, cnt)
register char *string;
register long cnt;
{
while (cnt) {
register int n = cnt >= maxchunk ? maxchunk : cnt;
if (read(fd, string, n) != n)
rd_fatal();
string += n;
cnt -= n;
}
}

15
commands/aal/rd_unsig2.c Executable file
View file

@ -0,0 +1,15 @@
/* $Header$ */
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
#include "object.h"
unsigned int
rd_unsigned2(fd)
{
char buf[2];
rd_bytes(fd, buf, 2L);
return uget2(buf);
}

42
commands/aal/sprint.c Executable file
View file

@ -0,0 +1,42 @@
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
/* $Header$ */
#if __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#include <system.h>
#include "param.h"
/*VARARGS*/
/*FORMAT1v $
%s = char *
%l = long
%c = int
%[uxbo] = unsigned int
%d = int
$ */
char *
#if __STDC__
sprint(char *buf, char *fmt, ...)
#else
sprint(buf, fmt, va_alist)
char *buf, *fmt;
va_dcl
#endif
{
va_list args;
#if __STDC__
va_start(args, fmt);
#else
va_start(args);
#endif
buf[_format(buf, fmt, args)] = '\0';
va_end(args);
return buf;
}

24
commands/aal/system.c Executable file
View file

@ -0,0 +1,24 @@
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
/* RCS: $Header$ */
#include <system.h>
File _sys_ftab[SYS_NOPEN] = {
{ 0, OP_READ},
{ 1, OP_APPEND},
{ 2, OP_APPEND}
};
File *
_get_entry()
{
register File *fp;
for (fp = &_sys_ftab[0]; fp < &_sys_ftab[SYS_NOPEN]; fp++)
if (fp->o_flags == 0)
return fp;
return (File *)0;
}

47
commands/aal/system.h Executable file
View file

@ -0,0 +1,47 @@
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
/* RCS: $Header$ */
#ifndef __SYSTEM_INCLUDED__
#define __SYSTEM_INCLUDED__
struct _sys_fildes {
int o_fd; /* UNIX filedescriptor */
int o_flags; /* flags for open; 0 if not used */
};
typedef struct _sys_fildes File;
extern File _sys_ftab[];
/* flags for sys_open() */
#define OP_READ 01
#define OP_WRITE 02
#define OP_APPEND 04
/* flags for sys_access() */
#define AC_EXIST 00
#define AC_READ 04
#define AC_WRITE 02
#define AC_EXEC 01
/* flags for sys_stop() */
#define S_END 0
#define S_EXIT 1
#define S_ABORT 2
/* standard file decsriptors */
#define STDIN &_sys_ftab[0]
#define STDOUT &_sys_ftab[1]
#define STDERR &_sys_ftab[2]
/* maximum number of open files */
#define SYS_NOPEN 20
/* return value for sys_break */
#define ILL_BREAK ((char *)0)
/* system's idea of block */
#define BUFSIZ 1024
#endif __SYSTEM_INCLUDED__

16
commands/aal/varargs.h Executable file
View file

@ -0,0 +1,16 @@
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
/* $Header$ */
#ifndef _VARARGS_H
#define _VARARGS_H
typedef char *va_list;
# define __va_sz(mode) (((sizeof(mode) + sizeof(int) - 1) / sizeof(int)) * sizeof(int))
# define va_dcl int va_alist;
# define va_start(list) (list = (char *) &va_alist)
# define va_end(list)
# define va_arg(list,mode) (*((mode *)((list += __va_sz(mode)) - __va_sz(mode))))
#endif /* _VARARGS_H */

28
commands/aal/wr_arhdr.c Executable file
View file

@ -0,0 +1,28 @@
/* $Header$ */
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
#include <arch.h>
#include "object.h"
wr_arhdr(fd, arhdr)
register struct ar_hdr *arhdr;
{
char buf[AR_TOTAL];
register char *c = buf;
register char *p = arhdr->ar_name;
register int i = 14;
while (i--) {
*c++ = *p++;
}
put2((int)(arhdr->ar_date>>16),c); c += 2;
put2((int)(arhdr->ar_date),c); c += 2;
*c++ = arhdr->ar_uid;
*c++ = arhdr->ar_gid;
put2(arhdr->ar_mode,c); c += 2;
put2((int)(arhdr->ar_size>>16),c); c += 2;
put2((int)(arhdr->ar_size),c);
wr_bytes(fd, buf, (long) AR_TOTAL);
}

30
commands/aal/wr_bytes.c Executable file
View file

@ -0,0 +1,30 @@
/* $Header$ */
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
#define MININT (1 << (sizeof(int) * 8 - 1))
#define MAXCHUNK (~MININT) /* Highest count we write(2). */
/* Notice that MAXCHUNK itself might be too large with some compilers.
You have to put it in an int!
*/
static int maxchunk = MAXCHUNK;
/*
* Just write "cnt" bytes to file-descriptor "fd".
*/
wr_bytes(fd, string, cnt)
register char *string;
register long cnt;
{
while (cnt) {
register int n = cnt >= maxchunk ? maxchunk : cnt;
if (write(fd, string, n) != n)
wr_fatal();
string += n;
cnt -= n;
}
}

14
commands/aal/wr_int2.c Executable file
View file

@ -0,0 +1,14 @@
/* $Header$ */
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
#include "object.h"
wr_int2(fd, i)
{
char buf[2];
put2(i, buf);
wr_bytes(fd, buf, 2L);
}

15
commands/aal/wr_long.c Executable file
View file

@ -0,0 +1,15 @@
/* $Header$ */
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
#include "object.h"
wr_long(fd, l)
long l;
{
char buf[4];
put4(l, buf);
wr_bytes(fd, buf, 4L);
}

36
commands/aal/wr_ranlib.c Executable file
View file

@ -0,0 +1,36 @@
/* $Header$ */
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
#include <ranlib.h>
#include "object.h"
wr_ranlib(fd, ran, cnt)
register struct ranlib *ran;
register long cnt;
{
#if ! (BYTES_REVERSED || WORDS_REVERSED)
if (sizeof (struct ranlib) != SZ_RAN)
#endif
{
char buf[100 * SZ_RAN];
while (cnt) {
register int i = (cnt > 100) ? 100 : cnt;
register char *c = buf;
long j = i * SZ_RAN;
cnt -= i;
while (i--) {
put4(ran->ran_off,c); c += 4;
put4(ran->ran_pos,c); c += 4;
ran++;
}
wr_bytes(fd, buf, j);
}
}
#if ! (BYTES_REVERSED || WORDS_REVERSED)
else wr_bytes(fd, (char *) ran, cnt * SZ_RAN);
#endif
}

17
commands/aal/write.c Executable file
View file

@ -0,0 +1,17 @@
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
/* $Header$ */
#include <system.h>
int
sys_write(fp, bufptr, nbytes)
File *fp;
char *bufptr;
int nbytes;
{
if (! fp) return 0;
return write(fp->o_fd, bufptr, nbytes) == nbytes;
}

63
commands/advent/Makefile Executable file
View file

@ -0,0 +1,63 @@
# Makefile for advent
# Where to put the adventure text files, and the binary executable.
# Need the trailing "/"s.
TEXTDIR = /usr/lib/advent/
BINDIR = /usr/bin
# Flags you may want to add to CFLAGS:
# -DHAS_STDC=0 or 1 We have Standard C. Default=1 iff __STDC__ is nonzero.
CC = cc
CFLAGS = -D_POSIX_SOURCE
LDFLAGS = -i
OBJS = advent.o database.o english.o initial.o itverb.o score.o\
travel.o turn.o utility.o verb.o vocab.o
DAT = advent1.dat advent2.dat advent3.dat advent4.dat
INSTDAT = $(TEXTDIR)advent1.dat $(TEXTDIR)advent2.dat \
$(TEXTDIR)advent3.dat $(TEXTDIR)advent4.dat
all: $(DAT) advent
install: $(TEXTDIR) $(INSTDAT) $(BINDIR)/advent
$(TEXTDIR):
install -d -o bin $(TEXTDIR)
$(TEXTDIR)advent1.dat: advent1.dat
install -c -o bin $? $@
$(TEXTDIR)advent2.dat: advent2.dat
install -c -o bin $? $@
$(TEXTDIR)advent3.dat: advent3.dat
install -c -o bin $? $@
$(TEXTDIR)advent4.dat: advent4.dat
install -c -o bin $? $@
$(BINDIR)/advent: advent
install -cs -o bin $? $@
advent: $(OBJS)
$(CC) $(LDFLAGS) -o advent $(OBJS)
setup: setup.c advent.h
$(CC) $(CFLAGS) $(LDFLAGS) -o setup setup.c
advtext.h advent1.dat advent2.dat advent3.dat advent4.dat: \
setup advent1.txt advent2.txt advent3.txt advent4.txt
./setup
advent.o: advent.h advdec.h advent.c
$(CC) -c $(CFLAGS) -DTEXTDIR='"$(TEXTDIR)"' advent.c
database.o: advent.h advdec.h advtext.h
travel.o: advent.h advdec.h advcave.h
initial.o english.o itverb.o score.o turn.o utility.o\
verb.o vocab.o: advent.h advdec.h
clean:
@rm -f *.o *.BAK *.dat advtext.h core advent setup

1357
commands/advent/advcave.h Executable file

File diff suppressed because it is too large Load diff

71
commands/advent/advdec.h Executable file
View file

@ -0,0 +1,71 @@
/* header ADVDEC.H *
* WARNING: GLOBAL (EXTERNAL) declarations for adventure */
#ifndef EXTERN /* #define as '' to define the variables */
#define EXTERN extern
#endif
EXTERN boolean gaveup; /* TRUE if he quits early */
EXTERN FILE *fd1, *fd2, *fd3, *fd4;
/*
English variables
*/
EXTERN char *vtxt[MAXWORDS], *iotxt[MAXITEMS], *otxt[MAXITEMS];
EXTERN int verbs[MAXWORDS], objs[MAXITEMS], iobjs[MAXITEMS];
EXTERN int vrbx, objx, iobx;
EXTERN int verb, object, motion, iobj, prep;
EXTERN boolean newtravel, is_wiz;
/*
Play variables
*/
extern int plac[MAXOBJ]; /* initial location */
extern int fixd[MAXOBJ];
struct playinfo {
int turns;
int loc, oldloc, oldloc2, newloc; /* location variables */
long loc_attrib[MAXLOC+1]; /* location status */
int place[MAXOBJ]; /* object location */
int fixed[MAXOBJ]; /* second object loc */
int weight[MAXOBJ];
int atloc[MAXLOC+1];
int link[MAXOBJ * 2];
int holder[MAXOBJ];
int hlink[MAXOBJ];
int visited[MAXLOC+1]; /* >0 if has been here */
int prop[MAXOBJ]; /* status of object */
long obj_state[MAXOBJ];
long points[MAXOBJ];
int hinted[HNTMAX+1];
int hints[HNTMAX+1][5];
int hintlc[HNTMAX+1];
int tally, tally2; /* item counts */
int limit; /* time limit */
int lmwarn; /* lamp warning flag */
int wzdark, closing, closed; /* game state flags */
int holding; /* count of held items */
int detail; /* LOOK count */
int knfloc; /* knife location */
int clock, clock2, panic; /* timing variables */
int dloc[DWARFMAX+1]; /* dwarf locations */
int dflag; /* dwarf flag */
int dseen[DWARFMAX+1]; /* dwarf seen flag */
int odloc[DWARFMAX+1]; /* dwarf old locations */
int daltloc; /* alternate appearance */
int dkill; /* dwarves killed */
int chloc, chloc2; /* chest locations */
int bonus; /* to pass to end */
int numdie; /* number of deaths */
int foobar; /* fee fie foe foo... */
int combo; /* combination for safe */
boolean terse;
int abbnum;
int health;
int chase;
boolean flg239;
int lastglob; /* to get space req. */
};
extern struct playinfo g;

136
commands/advent/advent.c Executable file
View file

@ -0,0 +1,136 @@
/** Adventure translated from Fortran to "C"
and ported to Minix by:
Robert R. Hall
San Diego, Calif 92115
hall@crash.cts.com
*/
/** program ADVENT.C *
* "advent.c" allocates GLOBAL storage space by *
* #defining EXTERN before #including "advdec.h". */
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <errno.h>
#include "advent.h" /* #define preprocessor equates */
#include "advdec.h"
#ifndef TEXTDIR
#define TEXTDIR ""
#endif
char textdir[] = TEXTDIR; /* directory where text files
live. */
_PROTOTYPE(int main, (int, char **));
_PROTOTYPE(static void opentxt, (void));
_PROTOTYPE(static void file_error, (char *));
int main(argc, argv)
int argc;
char **argv;
{
opentxt();
initialize();
rspeak(325);
if (argc == 2)
restore(argv[1]);
else {
g.hinted[3] = yes(65, 1, 0);
g.limit = (g.hinted[3] ? 800 : 550);
}
gaveup = FALSE;
srand((unsigned) time(NULL)); /* seed random */
while (!gaveup)
turn();
fclose(fd1);
fclose(fd2);
fclose(fd3);
fclose(fd4);
return (EXIT_SUCCESS); /* exit = ok */
} /* main */
/*
Open advent?.txt files
*/
static void opentxt()
{
static char filename[sizeof(textdir) + 16];
static FILE **fp[] = {0, &fd1, &fd2, &fd3, &fd4};
int i;
for (i = 1; i <= 4; i++) {
sprintf(filename, "%sadvent%d.dat", textdir, i);
*fp[i] = fopen(filename, "r");
if (!*fp[i])
file_error(filename);
}
}
/*
save adventure game
*/
void saveadv(username)
char *username;
{
int cnt;
FILE *savefd;
savefd = fopen(username, "wb");
if (savefd == NULL) {
perror(username);
return;
}
cnt = fwrite((void *) &g, 1, sizeof(struct playinfo), savefd);
if (cnt != sizeof(struct playinfo)) {
fprintf(stderr, "wrote %d of %u bytes\n",
cnt, (unsigned) sizeof(struct playinfo));
if (ferror(savefd)) {
fprintf(stderr, "errno is: 0x%.4x\n", errno);
perror(username);
}
}
if (fclose(savefd) == -1) {
perror(username);
}
printf("Saved in %s.\n", username);
return;
}
/*
restore saved game handler
*/
void restore(username)
char *username;
{
int cnt;
FILE *restfd;
restfd = fopen(username, "rb");
if (restfd == NULL)
file_error(username);
cnt = fread((void *) &g, 1, sizeof(struct playinfo), restfd);
if (cnt != sizeof(struct playinfo)) {
fprintf(stderr, "read %d bytes, expected %u\n",
cnt, (unsigned) sizeof(struct playinfo));
if (ferror(restfd)) {
fprintf(stderr, "errno is: 0x%.4x\n", errno);
perror(username);
}
}
if (fclose(restfd) == -1) {
perror(username);
}
printf("Restored from %s.\n", username);
return;
}
static void file_error(filename)
char *filename;
{
perror(filename);
exit(EXIT_FAILURE);
}

405
commands/advent/advent.h Executable file
View file

@ -0,0 +1,405 @@
/* header ADVENT.H *
* WARNING: HEADER file for all adventure modules */
#ifndef EXIT_FAILURE
#define EXIT_FAILURE 1
#define EXIT_SUCCESS (!(EXIT_FAILURE))
#endif
#define INPUTBUFLEN 80 /* Max input line length */
typedef int boolean;
#define FALSE (0)
#define TRUE (!FALSE)
#define MAXOBJ 123 /* max # of objects in cave */
#define MAXLOC 248 /* max # of cave locations */
#define WORDSIZE 20 /* max # of chars in commands */
#define MAXMSG 408 /* max # of long location descr */
#define HNTMAX 18 /* max # of hints */
#define HNTMIN 7 /* hints starting count */
#define MAXWORDS 25
#define MAXITEMS 45
#define CLASS(word) ((word)<0 ? -((-(word)) / 1000) : (word) / 1000)
#define VAL(word) ((word)<0 ? -((-(word)) % 1000) : (word) % 1000)
#define MAXTRAV (23+1) /* max # of travel directions from loc */
/* +1 for terminator travel[x].tdest=-1 */
#define DWARFMAX 6 /* max # of nasty dwarves */
#define MAXDIE 3 /* max # of deaths before close */
#define MAXTRS 79 /* max # of */
#define Y2 33
/*
Object definitions
*/
#define ANVIL 91
#define AXE 28
#define BATTERIES 39
#define BEAR 35
#define BEES 87
#define BILLBD 116
#define BIRD 101
#define BOAT 48
#define BOOK 110
#define BOOK2 BOOK + 1
#define BOOTH 93
#define BOTTLE 20
#define BRUSH 114
#define CAGE 4
#define CAKES 107
#define CARVNG 115
#define CASK 71
#define CHAIN 64
#define CHASM 21
#define CHASM2 CHASM + 1
#define CHEST 55
#define CLAM 14
#define CLOAK 47
#define COINS 54
#define CROWN 66
#define DOG 98
#define DOOR 41 /* giant door */
#define DRAGON 31
#define DWARF 17
#define EGGS 56
#define EMERALD 59
#define FISSURE 12
#define FLOWER 46
#define FLY 69
#define FOOD 19
#define GNOME 105
#define GRAIL 70
#define GRATE 3
#define HIVE 97
#define HONEY 96
#define HORN 52
#define JEWELS 53
#define KEYS 102
#define KNIFE 18
#define LAMP 2
#define LYRE 68
#define MAGAZINE 16
#define MESSAGE 36
#define MIRROR 23
#define MUSHRM 106
#define NUGGET 50
#define OIL 83
#define OIL2 OIL + 1
#define OYSTER 15
#define PLAGUE 125
#define PEARL 61
#define PHONE 94
#define PILLOW 10
#define PLANT 24
#define PLANT2 PLANT + 1
#define POLE 9
#define POSTER 113
#define PYRAMID 60
#define RADIUM 119
#define RING 72
#define ROCKS 92
#define ROD 5
#define ROD2 ROD + 1
#define RUG 62
#define SAFE 112
#define SAPPHIRE 69
#define SHIELD 118
#define SHOES 67
#define SKEY 90
#define SLUGS 95
#define SNAKE 11
#define SPHERE 120
#define SPICES 63
#define SPIDER 121
#define STEPS 7
#define STICKS 49
#define SWORD 65
#define TABLET 13
#define TDOOR 42 /* tiny door */
#define TDOOR2 TDOOR + 1 /* wrought-iron door */
#define PDOOR TDOOR2 + 1 /* door to phone booth */
#define TRIDENT 57
#define TROLL 33
#define TROLL2 TROLL + 1
#define VASE 58
#define VEND 38
#define WALL 88
#define WALL2 WALL + 1
#define WATER 81 /* in bottle */
#define WATER2 WATER + 1 /* in cask */
#define WINE 85 /* in bottle */
#define WINE2 WINE + 1 /* in cask */
#define WUMPUS 99
/*
Verb definitions
*/
#define BACK 8
#define CAVE 67
#define DEPRESSION 63
#define ENTRANCE 64
#define EXIT 11
#define NULLX 21
/*
Action verb definitions
*/
#define TAKE 1
#define DROP 2
#define SAY 3
#define OPEN 4
#define NOTHING 5
#define CLOSE 6
#define ON 7
#define OFF 8
#define WAVE 9
#define CALM 10
#define WALK 11
#define KILL 12
#define POUR 13
#define EAT 14
#define DRINK 15
#define RUB 16
#define THROW 17
#define QUIT 18
#define FIND 19
#define INVENTORY 20
#define FEED 21
#define FILL 22
#define BLAST 23
#define SCORE 24
#define FOO 25
#define BRIEF 26
#define READ 27
#define BREAK 28
#define WAKE 29
#define SUSPEND 30
#define RESTORE 31
#define YANK 32
#define WEAR 33
#define HIT 34
#define ANSWER 35
#define BLOW 36
#define LEAVE 37
#define YELL 38
#define DIAL 39
#define PLAY 40
#define PICK 41
#define PUT 42
#define TURN 43
#define GET 44
#define INSRT 45
#define REMOVE 46
#define BURN 47
#define GRIPE 48
#define LOCK 49
#define UNLOCK 50
#define HEALTH 51
#define LOOK 52
#define COMBO 53
#define SWEEP 54
#define TERSE 55
#define WIZ 56
#define MAP 57
#define GATE 58
#define PIRLOC 59
#define GO 11
#define SHUT 6
#define LOG 33
#define MOTION 0 /* CLASSD */
#define NOUN 1 /* CLASSN */
#define ACTION 2 /* CLASSA */
#define MISC 3 /* CLASSM */
#define PREPOSITION 4 /* CLASSP */
#define ADJACTIVE 5 /* CLASSJ */
#define CONJUNCTION 6 /* CLASSC */
/*
and a few preposition. prefix PREP to distinguish them from
verbs or nouns
*/
#define PREPAT 9
#define PREPDN 8
#define PREPIN 1
#define PREPFR 5
#define PREPOF 6
#define PREPOFF 6
#define PREPON 2
/*
BIT mapping of "cond" array which indicates location status
*/
#define LIGHT 1
#define WATOIL 2
#define LIQUID 4
#define NOPIRAT 16
/* Object condition bit functions */
#define OPENBT 2
#define LOCKBT 4
#define BURNBT 6
#define DEADBT 10
#define WEARBT 12
/*
Structure definitions
*/
struct wac {
char *aword;
int acode;
};
struct trav {
int tdest;
int tverb;
int tcond;
};
/* Function prototypes.
"#if (__STDC__)" should have been be enough,
but some compilers are stupid, so allow Makefile to say -DHAS_STDC=whatever.
*/
#if defined(HAS_STDC) ? (HAS_STDC) : (__STDC__)
#undef HAS_STDC
#define HAS_STDC 1
#define _PROTOTYPE(function, params) function params
#define _CONST const
#else
#define _PROTOTYPE(function, params) function ()
#define _CONST
#endif
/* Advent.c */
_PROTOTYPE(void saveadv, (char *username));
_PROTOTYPE(void restore, (char *username));
/* Initialize.c */
_PROTOTYPE(void initialize, (void));
/* Database.c */
_PROTOTYPE(int yes, (int msg1, int msg2, int msg3));
_PROTOTYPE(void rspeak, (int msg));
_PROTOTYPE(void pspeak, (int item, int state));
_PROTOTYPE(void desclg, (int loc));
_PROTOTYPE(void descsh, (int loc));
/* English.c */
_PROTOTYPE(int english, (void));
_PROTOTYPE(int analyze, (char *word, int *type, int *value));
/* Itverb.c */
_PROTOTYPE(void itverb, (void));
_PROTOTYPE(void ivblast, (void));
_PROTOTYPE(void ivlook, (void));
/* Turn.c */
_PROTOTYPE(void turn, (void));
_PROTOTYPE(void describe, (void));
_PROTOTYPE(void descitem, (void));
_PROTOTYPE(void dwarfend, (void));
_PROTOTYPE(void normend, (void));
_PROTOTYPE(void score, (int));
_PROTOTYPE(void death, (void));
_PROTOTYPE(char *probj, (void));
_PROTOTYPE(void trobj, (void));
_PROTOTYPE(void dwarves, (void));
_PROTOTYPE(void dopirate, (void));
_PROTOTYPE(int stimer, (void));
/* Verb.c */
_PROTOTYPE(void trverb, (void));
_PROTOTYPE(void vtake, (void));
_PROTOTYPE(void vdrop, (void));
_PROTOTYPE(void vopen, (void));
_PROTOTYPE(void vsay, (void));
_PROTOTYPE(void von, (void));
_PROTOTYPE(void voff, (void));
_PROTOTYPE(void vwave, (void));
_PROTOTYPE(void vkill, (void));
_PROTOTYPE(void vpour, (void));
_PROTOTYPE(void veat, (void));
_PROTOTYPE(void vdrink, (void));
_PROTOTYPE(void vthrow, (void));
_PROTOTYPE(void vfind, (void));
_PROTOTYPE(void vfill, (void));
_PROTOTYPE(void vfeed, (void));
_PROTOTYPE(void vread, (void));
_PROTOTYPE(void vbreak, (void));
_PROTOTYPE(void vwake, (void));
_PROTOTYPE(void actspk, (int verb));
_PROTOTYPE(void vyank, (void));
_PROTOTYPE(void vwear, (void));
_PROTOTYPE(void vlock, (void));
_PROTOTYPE(void vunlock, (void));
_PROTOTYPE(void vclose, (void));
/* Utility.c */
_PROTOTYPE(boolean ajar, (int));
_PROTOTYPE(boolean at, (int item));
_PROTOTYPE(boolean athand, (int));
_PROTOTYPE(void bitoff, (int, int));
_PROTOTYPE(void biton, (int, int));
_PROTOTYPE(boolean bitset, (long, int));
_PROTOTYPE(boolean blind, (void));
_PROTOTYPE(int burden, (int));
_PROTOTYPE(void carry, (int obj, int where));
_PROTOTYPE(int confuz, (void));
_PROTOTYPE(boolean dark, (void));
_PROTOTYPE(boolean dcheck, (void));
_PROTOTYPE(boolean dead, (int));
_PROTOTYPE(void drop, (int obj, int where));
_PROTOTYPE(void destroy, (int obj));
_PROTOTYPE(boolean edible, (int));
_PROTOTYPE(boolean enclosed, (int));
_PROTOTYPE(void extract, (int));
_PROTOTYPE(boolean forced, (int atloc));
_PROTOTYPE(boolean here, (int item));
_PROTOTYPE(boolean hinged, (int));
_PROTOTYPE(boolean holding, (int));
_PROTOTYPE(void insert, (int, int));
_PROTOTYPE(boolean inside, (int));
_PROTOTYPE(void juggle, (int loc));
_PROTOTYPE(int liq, (int));
_PROTOTYPE(int liqloc, (int loc));
_PROTOTYPE(int liq2, (int pbottle));
_PROTOTYPE(boolean living, (int));
_PROTOTYPE(boolean locked, (int));
_PROTOTYPE(boolean locks, (int));
_PROTOTYPE(void lookin, (int));
_PROTOTYPE(void move, (int obj, int where));
_PROTOTYPE(int noway, (void));
_PROTOTYPE(boolean opaque, (int));
_PROTOTYPE(boolean outside, (int));
_PROTOTYPE(boolean pct, (int x));
_PROTOTYPE(boolean plural, (int));
_PROTOTYPE(boolean portal, (int));
_PROTOTYPE(boolean printed, (int));
_PROTOTYPE(int put, (int obj, int where, int pval));
_PROTOTYPE(int ranz, (int));
_PROTOTYPE(boolean small, (int));
_PROTOTYPE(boolean toting, (int item));
_PROTOTYPE(boolean treasr, (int));
_PROTOTYPE(boolean vessel, (int));
_PROTOTYPE(boolean wearng, (int));
_PROTOTYPE(boolean worn, (int));
_PROTOTYPE(void bug, (unsigned int n));
_PROTOTYPE(char *ask, (char *prompt, char *buf, int buflen));
_PROTOTYPE(void panic, (char *msg, boolean save));
/* travel.c */
_PROTOTYPE(void domove, (void));
_PROTOTYPE(void gettrav, (int loc, struct trav *travel));
/* vocab.c */
_PROTOTYPE(int vocab, (char *word, int val));

827
commands/advent/advent1.txt Executable file
View file

@ -0,0 +1,827 @@
#1
You are standing at the end of a road before a small brick building.
Around you is a forest. A small stream flows out of the building and
down a gully.
#2
You have walked up a hill, still in the forest. The road slopes back
down the other side of the hill. There is a building in the distance.
#3
You are inside a building, a well house for a large spring. Off
to one side is a small pantry.
#4
You are in a valley in the forest beside a stream tumbling along a
rocky bed.
#5
You are in open forest, with a deep valley to one side. Not far
is a large billboard.
#6
You are in open forest near both a valley and a road.
#7
At your feet all the water of the stream splashes into a 2-inch slit
in the rock. Downstream the stream bed is bare rock.
#8
You are in a 20-foot depression floored with bare dirt. Set into the
dirt is a strong steel grate mounted in concrete. A dry stream bed
leads into the depression.
#9
You are in a small chamber beneath a 3x3 steel grate to the surface.
A low crawl over cobbles leads inward to the west.
#10
You are crawling over cobbles in a low passage. There is a dim light
at the east end of the passage.
#11
You are in a debris room filled with stuff washed in from the surface.
A low wide passage with cobbles becomes plugged with mud and debris
here, but an awkward canyon leads upward and west. A note on the wall
says "Magic Word XYZZY".
#12
You are in an awkward sloping east/west canyon.
#13
You are in a splendid chamber thirty feet high. The walls are frozen
rivers of orange stone. An awkward canyon and a good passage exit
from east and west sides of the chamber.
#14
At your feet is a small pit breathing traces of white mist. An east
passage ends here except for a small crack leading on.
#15
You are at one end of a vast hall stretching forward out of sight to
the west. There are openings to either side. Nearby, a wide stone
staircase leads downward. The hall is filled with wisps of white mist
swaying to and fro almost as if alive. A cold wind blows up the
staircase. There is a passage at the top of a dome behind you.
#16
The crack is far too small for you to follow.
#17
You are on the east bank of a fissure slicing clear across the hall.
The mist is quite thick here, and the fissure is too wide to jump.
#18
This is a low room with a crude note on the wall. The note says,
"You won't get it up the steps".
#19
You are in the Hall of the Mountain King, with passages off in all
directions.
#20
You are at the bottom of the pit with a broken neck.
#21
You didn't make it.
#22
The dome is unclimbable.
#23
You are at the west end of the Twopit Room. There is a large hole in
the wall above the pit at this end of the room.
#24
You are at the bottom of the eastern pit in the Twopit Room. There is
a small pool of oil in one corner of the pit.
#25
You are at the bottom of the western pit in the Twopit Room. There is
a large hole in the wall about 25 feet above you.
#26
You clamber up the plant and scurry through the hole at the top.
#27
You are on the west side of the fissure in the Hall of Mists.
#28
You are in a low N/S passage at a hole in the floor. The hole goes
down to an E/W passage.
#29
You are in the South Side Chamber.
#30
You are in the West Side Chamber of the Hall of the Mountain King.
A passage continues west and up here.
#31
<$$<
#32
You can't get by the snake.
#33
You are in a large room, with a passage to the south, a passage to the
west, and a wall of broken rock to the east. There is a large "Y2" on
a rock in the room's center.
#34
You are in a jumble of rock, with cracks everywhere.
#35
You're at a low window overlooking a huge pit, which extends up out of
sight. A floor is indistinctly visible over 50 feet below. Traces of
white mist cover the floor of the pit, becoming thicker to the right.
Marks in the dust around the window would seem to indicate that
someone has been here recently. Directly across the pit from you and
25 feet away there is a similar window looking into a lighted room. A
shadowy figure can be seen there peering back at you.
#36
You are in a dirty broken passage. To the east is a crawl. To the
west is a large passage. Above you is a hole to another passage.
#37
You are on the brink of a small clean climbable pit. A crawl leads
west.
#38
You are in the bottom of a small pit with a little stream, which
enters and exits through tiny slits.
#39
You are in a large room full of dusty rocks. There is a big hole in
the floor. There are cracks everywhere, and a passage leading east.
#40
You have crawled through a very low wide passage parallel to and north
of the Hall of Mists.
#41
You are at the west end of Hall of Mists. A low wide crawl continues
west and another goes north. To the south is a little passage 6 feet
off the floor.
#42
You are in a maze of twisty little passages, all alike.
#43
You are in a maze of twisty little passages, all alike.
#44
You are in a maze of twisty little passages, all alike.
#45
You are in a maze of twisty little passages, all alike.
#46
Dead end.
#47
Dead end.
#48
Dead end.
#49
You are in a maze of twisty little passages, all alike.
#50
You are in a maze of twisty little passages, all alike.
#51
You are in a maze of twisty little passages, all alike.
#52
You are in a maze of twisty little passages, all alike.
#53
You are in a maze of twisty little passages, all alike.
#54
Dead end.
#55
You are in a maze of twisty little passages, all alike.
#56
Dead end.
#57
You are on the brink of a thirty foot pit with a massive orange column
down one wall. You could climb down here but you could not get back
up. The maze continues at this level.
#58
Dead end.
#59
You have crawled through a very low wide passage parallel to and north
of the Hall of Mists.
#60
You are at the east end of a very long hall apparently without side
chambers. In the south wall are several wide cracks and a high
hole, but the hole is far above your head. To the east a wide
crawl slants up. To the north a round two foot hole slants down.
#61
You are at the west end of a very long featureless hall. The hall
joins up with a narrow north/south passage.
#62
You are at a crossover of a high N/S passage and a low E/W one.
#63
Dead end.
#64
You are at a complex junction. A low hands and knees passage from the
north joins a higher crawl from the east to make a walking passage
going west. There is also a large room above. The air is damp here.
#65
You are in Bedquilt, a long east/west passage with holes everywhere.
To explore at random select north, south, up, or down.
#66
You are in a room whose walls resemble swiss cheese. Obvious passages
go west, east, NE, and NW. Part of the room is occupied by a large
bedrock block.
#67
You are at the east end of the Twopit Room. The floor here is
littered with thin rock slabs, which make it easy to descend the pits.
There is a path here bypassing the pits to connect passages from east
and west. There are holes all over, but the only big one is on the
wall directly over the west pit where you can't get to it.
#68
You are in a large low circular chamber whose floor is an immense slab
fallen from the ceiling (Slab Room). East and west there once were
large passages, but they are now filled with boulders. Low small
passages go north and south, and the south one quickly bends west
around the boulders.
#69
You are in a secret N/S canyon above a large room.
#70
You are in a secret N/S canyon above a sizable passage.
#71
You are in a secret canyon at a junction of three canyons, bearing
north, south, and SE. The north one is as tall as the other two
combined.
#72
You are in a large low room. Crawls lead north, NE, and SW.
#73
Dead end crawl.
#74
You are in a secret canyon which here runs E/W. It crosses over a
very tight canyon 15 feet below. If you go down you may not be able
to get back up.
#75
You are at a wide place in a very tight N/S canyon.
#76
The canyon here becomes too tight to go further south.
#77
You are in a tall E/W canyon. A low tight crawl goes 3 feet north and
seems to open up.
#78
The canyon runs into a mass of boulders -- dead end.
#79
The stream flows out through a pair of 1 foot diameter sewer pipes.
It would be advisable to use the exit.
#80
You are in a maze of twisty little passages, all alike.
#81
Dead end.
#82
Dead end.
#83
You are in a maze of twisty little passages, all alike.
#84
You are in a maze of twisty little passages, all alike.
#85
Dead end.
#86
Dead end.
#87
You are in a maze of twisty little passages, all alike.
#88
You are in a long, narrow corridor stretching out of sight to the
west. At the eastern end is a hole through which you can see a
profusion of leaves.
#89
There is nothing here to climb. Use "up" or "out" to leave the pit.
#90
You have climbed up the plant and out of the pit.
#91
You are at the top of a steep incline above a large room. You could
climb down here, but you would not be able to climb up. There is a
passage leading back to the north.
#92
You are in the Giant Room. The ceiling here is too high up for your
lamp to show it. Cavernous passages lead east, north, and south. On
the west wall is scrawled the inscription, "FEE FIE FOE FOO" [sic].
#93
The passage here is blocked by a recent cave-in.
#94
You are at one end of an immense north/south passage.
#95
You are in a magnificent cavern with a rushing stream, which cascades
over a sparkling waterfall into a roaring whirlpool which disappears
through a hole in the floor. Passages exit to the south and west.
#96
You are in the Soft Room. The walls are covered with heavy curtains,
the floor with a thick pile carpet. Moss covers the ceiling.
#97
This is the Oriental Room. Ancient oriental cave drawings cover the
walls. A gently sloping passage leads upward to the north, another
passage leads SE, and a hands and knees crawl leads east.
#98
You are following a wide path around the outer edge of a large cavern.
Far below, through a heavy white mist, strange splashing noises can be
heard. The mist rises up through a fissure in the ceiling. The path
hugs the cavern's rim to the NE and south, while another branch forks
west. A round chute with extremely smooth walls angles sharply up
to the southwest.
#99
You are in an alcove. A small NW path seems to widen after a short
distance. An extremely tight tunnel leads east. It looks like a very
tight squeeze. An eerie light can be seen at the other end.
#100
You're in a small chamber lit by an eerie green light. An extremely
narrow tunnel exits to the west, and a dark corridor leads NE.
#101
You're in the Dark-Room. A corridor leading south is the only exit.
#102
You are in an arched hall. A coral passage once continued up and east
from here, but is now blocked by debris. The air smells of sea water.
#103
You're in a large room carved out of sedimentary rock. The floor and
walls are littered with bits of shells imbedded in the stone. A
shallow passage proceeds downward, and a somewhat steeper one leads
up. A low hands and knees passage enters from the south.
#104
You are in a long sloping corridor with ragged sharp walls.
#105
You are in a cul-de-sac about eight feet across.
#106
You are in an anteroom leading to a large passage to the east. Small
passages go west and up. The remnants of recent digging are evident.
A sign in midair here says "Cave under construction beyond this point.
Proceed at own risk. [Witt Construction Company]".
#107
You are in a maze of twisty little passages, all different.
#108
You are at Witt's End. Passages lead off in *ALL* directions.
#109
You are in a north/south canyon about 25 feet across. The floor is
covered by white mist seeping in from the north. The walls extend
upward for well over 100 feet. Suspended from some unseen point far
above you, an enormous two-sided mirror is hanging parallel to and
midway between the canyon walls. (The mirror is obviously provided
for the use of the dwarves, who as you know, are extremely vain.) A
small window can be seen in either wall, some fifty feet up.
#110
You're at a low window overlooking a huge pit, which extends up out of
sight. A floor is indistinctly visible over 50 feet below. Traces of
white mist cover the floor of the pit, becoming thicker to the left.
Marks in the dust around the window would seem to indicate that
someone has been here recently. Directly across the pit from you and
25 feet away there is a similar window looking into a lighted room. A
shadowy figure can be seen there peering back at you.
#111
A large stalactite extends from the roof and almost reaches the floor
below. You could climb down it, and jump from it to the floor, but
having done so you would be unable to reach it to climb back up.
#112
You are in a little maze of twisting passages, all different.
#113
You are at the edge of a large underground reservoir. An opaque cloud
of white mist fills the room and rises rapidly upward. The lake is
fed by a stream, which tumbles out of a hole in the wall about 10 feet
overhead and splashes noisily into the water somewhere within the
mist. The indistinct shape of the opposite shore can be dimly seen
through the mist. The only passage goes back toward the south.
#114
Dead end.
#115
You are at the northeast end of an immense room, even larger than the
Giant Room. It appears to be a repository for the "ADVENTURE"
program. Massive torches far overhead bathe the room with smoky
yellow light. Scattered about you can be seen a pile of bottles (all
of them empty), a nursery of young beanstalks murmuring quietly, a bed
of oysters, a bundle of black rods with rusty stars on their ends, and
a collection of brass lanterns. Off to one side a great many dwarves
are sleeping on the floor, snoring loudly. A sign nearby reads: "Do
not disturb the dwarves!" An immense mirror is hanging against one
wall, and stretches to the other end of the room, where various other
sundry objects can be glimpsed dimly in the distance. An unoccupied
telephone booth stands against the north wall.
#116
You are at the southwest end of the repository. To one side is a pit
full of fierce green snakes. On the other side is a row of small
wicker cages, each of which contains a little sulking bird. In one
corner is a bundle of black rods with rusty marks on their ends. A
large number of velvet pillows are scattered about on the floor.
Beside one of the pillows is a large, dusty, leather-bound volume
with the title "History of Adventure" embossed in pure gold.
A vast mirror stretches off to the northeast, almost reaching the
phone booth. At your feet is a large steel grate, next to which is
a sign which reads, "Treasure Vault. Keys in Main Office."
#117
You are on one side of a large, deep chasm. A heavy white mist rising
up from below obscures all view of the far side. A SW path leads away
from the chasm into a winding corridor.
#118
You are in a long winding corridor sloping out of sight in both
directions.
#119
You are in a secret canyon which exits to the north and east.
#120
You are in a secret canyon which exits to the north and east.
#121
You are in a secret canyon which exits to the north and east.
#122
You are on the northeast side of a deep chasm. A NE path leads away
from the chasm on this side.
#123
You're in a long east/west corridor. A faint rumbling noise can be
heard in the distance.
#124
The path forks here. The left fork leads northeast. A dull rumbling
seems to get louder in that direction. The right fork leads southeast
down a gentle slope. The main corridor enters from the west.
#125
The walls are quite warm here. From the north can be heard a steady
roar, so loud that the entire cave seems to be trembling. Another
passage leads south, and a low crawl goes east.
#126
You are on the edge of a breathtaking view. Far below you is an
active volcano, from which great gouts of molten lava come surging
out, cascading back down into the depths. The glowing rock fills the
farthest reaches of the cavern with a blood-red glare, giving every-
thing an eerie, macabre appearance. The air is filled with flickering
sparks of ash and a heavy smell of brimstone. The walls are hot to
the touch, and the thundering of the volcano drowns out all other
sounds. Embedded in the jagged roof far overhead are myriad twisted
formations composed of pure white alabaster, which scatter the murky
light into sinister apparitions upon the walls. To one side is a deep
gorge, filled with a bizarre chaos of tortured rock which seems to
have been crafted by the devil himself. An immense river of fire
crashes out from the depths of the volcano, burns its way through the
gorge, and plummets into a bottomless pit far off to your left. To
the right, an immense geyser of blistering steam erupts continuously
from a barren island in the center of a sulfurous lake, which bubbles
ominously. The far right wall is aflame with an incandescence of its
own, which lends an additional infernal splendor to the already
hellish scene. A dark, foreboding passage exits to the south.
#127
You are in a small chamber filled with large boulders. The walls are
very warm, causing the air in the room to be almost stifling from the
heat. The only exit is a crawl heading west, through which is coming
a low rumbling.
#128
You are walking along a gently sloping north/south passage lined with
oddly shaped limestone formations.
#129
You are standing at the entrance to a large, barren room. A sign
posted above the entrance reads: "Caution! Bear in room!"
#130
You are inside a barren room. The center of the room is completely
empty except for some dust. Marks in the dust lead away toward the
far end of the room. The only exit is the way you came in.
#131
You are in a maze of twisting little passages, all different.
#132
You are in a little maze of twisty passages, all different.
#133
You are in a twisting maze of little passages, all different.
#134
You are in a twisting little maze of passages, all different.
#135
You are in a twisty little maze of passages, all different.
#136
You are in a twisty maze of little passages, all different.
#137
You are in a little twisty maze of passages, all different.
#138
You are in a maze of little twisting passages, all different.
#139
You are in a maze of little twisty passages, all different.
#140
Dead end.
#141
You are on a narrow promontory at the foot of a waterfall, which
spurts from an overhead hole in the rock wall and splashes into a
large reservoir, sending up clouds of mist and spray.
Through the thick white mist looms a polished marble slab, to
which is affixed an enormous rusty iron anvil. In golden letters
are written the words: "Whoso Pulleth Out This Sword of This
Stone and Anvil, is Right wise King-Born of All This Mountain."
There is a narrow chimney on the east side of the promontory.
#142
You are on a narrow shelf above and east of the top of a very steep
chimney. A long smooth granite slide curves down out of sight
to the east. If you go down the slide, you may not be able to
climb back up.
#143
You are in the private chamber of the Mountain King. Hewn into the
solid rock of the east wall of the chamber is an intricately-wrought
throne of elvish design. There is an exit to the west.
#144
You are on the east side of the throne room. On the arm of the throne
has been hung a sign which reads "Gone for the day: visiting
sick snake. --M.K."
#145
You are dragged down, down, into the depths of the whirlpool.
Just as you can no longer hold your breath, you are shot out over
a waterfall into the shallow end of a large reservoir. Gasping
and sputtering, you crawl weakly towards the shore....
#146
You are in dense forest, with a hill to one side. The trees appear
to thin out towards the north and east.
#147
You are at the high point of a wide grassy knoll, partially surrounded
by dense forest. The land rises to the south and east, and drops off
sharply to the north and west. The air smells of sea water.
#148
You are at the edge of a trackless salt marsh. Tall reeds obscure
the view.
#149
You're in salt marsh.
#150
You're in salty marsh.
#151
You are in salt marsh.
#152
Dead end.
#153
You're on a sandy beach at the edge of the open sea. The beach
ends a short distance south and the land rises to a point. To
the north, the beach ends cliffs and broken rocks.
#154
You are at a jumble of large broken rocks. A gentle path leads up
to the top of the nearby cliffs. A narrow treacherous path
disappears among the rocks at the foot of the cliff.
#155
You are on a high cliff overlooking the sea. Far below the
rolling breakers smash into a jumble of large broken rocks.
The thunder of the surf is deafening.
#156
You're at the bottom of the cliff, smashed to smithereens by the
pounding surf.
#157
You are at Thunder Hole, a funnel shaped cavern opening onto the sea.
The noise of the surf pounding against the outer rocks of the cave is
amplified by the peculiar shape of the cave, causing a thunder-like
booming sound to reverberate throughout the cave. Outside, a narrow
path leads south towards some large rocks.
#158
You are at the top of some arched steps. On one side is a blank wall
with a tiny door at the base and a shelf overhead. On the other side
a westward passage leads to the sea.
#159
You are in a low cramped chamber at the back of a small cave.
There is a shelf in the rock wall at about the height of your
shoulder.
#160
You are on a wide ledge, bounded on one side by a rock wall,
and on the other by a sheer cliff. The only way past is through
a large wrought-iron door.
#161
You feel dizzy...Everything around you is spinning, expanding,
growing larger.... Dear me! Is the cave bigger or are you smaller?
#162
You are again overcome by a sickening vertigo, but this time
everything around you is shrinking...Shrinking...
#163
You are again overcome by a sickening vertigo, but this time
everything is shrinking... I mean, you are growing. This is
terribly confusing!
#164
You feel dizzy...Everything around you is spinning, expanding,
growing larger....
#165
You're at the bottom of the cliff with a broken neck.
#166
You are at the western tip of the Blue Grotto. A large lake almost
covers the cavern floor, except for where you are standing. Small
holes high in the rock wall to the east admit a dim light. The
reflection of the light from the water suffuses the cavern with
a hazy bluish glow.
#167
You are on the shore of an underground sea. A high wooden
structure of vast proportions extends out into the water to the
east. The way west is through a wrought-iron door.
#168
You are on the eastern shore of the Blue Grotto. An ascending
tunnel disappears into the darkness to the SE.
#169
You are at a high rock on the NE side of a watery chamber at the mouth
of a small brook. An unknown gas bubbles up through the water from
the chamber floor. A bluish light can be seen to the southwest.
#170
You are in a windy tunnel between two large rooms.
#171
You are in the Bat Cave. The walls and ceiling are covered with
sleeping bats. The floor is buried by a mass of dry, foul-smelling
guano. The stench is overpowering. Exits to the NW and east.
#172
You are in a very tight N/S crack. The passage seems to widen to
the south.
#173
You are in a very tight N/S crack. The passage south is blocked
by a recent cave-in.
#174
You're in the Cloakroom. This is where the dreaded Wumpus repairs
to sleep off heavy meals. (Adventurers are his favorite dinner!)
Two very narrow passages exit NW and NE.
#175
You're in a room containing several small climbable pits. Passages
exit to the east and north.
#176
You are at the bottom of a small featureless pit.
#177
You are at a high hole in a rock wall.
#178
The NE passage is blocked by a recent cave-in.
#179
You are in a sloping muddy defile, next to a tumbling brook.
#180
You are in a level E/W passage partially blocked by an overhanging
tongue of rock. A steep scramble would take you up over the tongue,
whence continues an upward crawl.
#181
The dog won't let you pass.
#182
You're in the Upper Passage, a long level E/W tunnel.
#183
You are in a star-shaped chamber. Passages exit north, east, south,
and west.
#184
You are at an elbow in a winding E/W passage.
#185
Dead end.
#186
You're at the intersection of two long tunnels. One goes NW,
the other NE.
#187
You're in a long narrow east-west passage which curves out of sight
at both ends.
#188
You're in the Rotunda. Corridors radiate in all directions.
There is a telephone booth standing against the north wall.
#189
You are standing in a telephone booth at the side of a large chamber.
Hung on the wall is a banged-up pay telephone of ancient design.
#190
You're at the Devil's Chair, a large crystallization shaped like a
seat, at the edge of a black abyss. You can't see the bottom.
An upward path leads away from the abyss.
#191
You're in a dead-end crack.
#192
You're on a small gravel beach at the south wall of the Blue Grotto.
A gravelly path leads east.
#193
You are in the Flower Room. The walls are covered with colorful,
intricate, flowerlike patterns of crystallized gypsum. A hole leads
to the west.
#194
You are at the end of a short E/W corridor.
#195
You are looking west from the end of a short E/W corridor. At your
feet is a pile of loose rubble. On your left is a hole into another
chamber.
#196
You are in an arched hall. The remnants of a now-plugged coral
passage lie to the east. The north wall has partially crumbled,
exposing a large connecting hole to another room.
#197
You're in the Vestibule, a short east-west passage between two rooms.
#198
You are in the Fairy Grotto. All around you innumerable stalactites,
arranged in immense colonnades, form elegant arches. On every side
you hear the dripping of water, like the footsteps of a thousand
fairies. A small stream runs from the SW corner. A bright glow
emanates from the south side of the grotto, and a steep passage
descends to the east.
#199
You have approached the lower end of a steep passage, but it is
just too cold here to hang around, and you aren't properly equipped
to continue. With teeth chattering, you climb back up....
#200
You are in the Crystal Palace. An overhead vein of phosphorescent
quartz casts a luminous glow which is reflected by countless chips of
mica embedded in both walls, which consist of some sort of highly
reflective glass, apparently of volcanic origin. A winding path
of yellow sandstone leads west and rises steeply to the east.
#201
You are following a yellow sandstone path. There is a glow
to the west.
#202
You are in a very tall chamber whose walls are comprised of many
different rock strata. Layers of red and yellow sandstone
intertwine with bright bands of calcareous limestone in a rainbow-
like profusion of color. The rainbow effect is so real, you
are almost tempted to look for a pot of gold! Poised far over
your head, a gigantic slab, wedged tightly between the north and
south walls, forms a natural bridge across the roof of the chamber.
A trail leads east and west.
#203
You're in a steeply sloping passage. It is very cold here.
#204
You are in the Hall of Ice, in the deepest part of the caverns.
During winter, frigid outside air settles here, making this room
extremely cold all year round. The walls and ceilings are covered
with a thick coating of ice. An upward passage exits to the west.
#205
You are standing on a natural bridge far above the floor of a circular
chamber whose walls are a rainbow of multicolored rock. The bridge
was formed eons ago by a huge slab which fell from the ceiling and
is now jammed between the north and south walls of the chamber.
#206
You are in a low, wide room below another chamber. A small green
pond fills the center of the room. The lake is apparently spring
fed. A small stream exits through a narrow passage to the north.
A larger passage continues west.
#207
You are in a tight north/south crawl through a stratum of red
colored rock. The air is damp with mist.
#208
You are in a tall canyon on the south side of a swift, wide river.
Written in the mud in crude letters are the words: "You Have Found
Lost River." A wide path leads east and west along the bank. A tight
crawl way would take you south out of the canyon.
#209
You are standing on a large flat rock table at the western end of
Lost River Canyon. Beneath your feet, the river disappears amidst
foam and spray into a large sinkhole. A gentle path leads east
along the river's south shore. Another leads sharply upward along
the river's north side.
#210
You are at a niche in the canyon wall, far above a raging river.
The air is filled with mist and spray, making it difficult to see
ahead. A downward sloping ledge narrows to the east. The path
to the west is easier.
#211
The ledge is growing very narrow and treacherous, and falls off almost
vertically. You could go down, but you won't be able to climb back.
#212
You are standing in a telephone booth at the side of the Repository.
#213
You're at the east end of a level passage at a hole in the floor.
#214
You're at the north edge of a dark cove.
#215
You are in a dry granite basin, worn smooth eons ago by water
swirling down from a now-dry spillway.
#216
You're in a dry spillway east of and above a smooth rock basin.
#217
You are in the Winery, a cool dark room which extends some
distance off to the east.
#218
You are to the east of the Winery, where the room ends in a thicket
of high, sharp, pointed, climbable limestone pinnacles. There is a
narrow ledge just above the top of the spires. If you go up, it
might be difficult to get back down.
#219
You are in a high-vaulted cavern whose roof rises over fifty
meters to culminate in a series of pointed arches directly over
your head. There are also two low arches to either side, forming
side portals. The whole effect is that of a gothic cathedral.
You can proceed north, south, east, or west.
#220
You're at the east portal of the Gothic Cathedral. The path leads
east and west.
#221
You're at the west portal of the Gothic Cathedral.
#222
You are at the foot of the Altar, an immense, broad stalagmite.
An opening leads south.
#223
You're on top of an enormous, broad stalagmite. There is a hole
in the ceiling overhead.
#224
You are in a room the size and shape of a small crypt. A narrow
cut exits east. There is a hole in the floor.
#225
You are in the Gothic Chapel, a small chamber adjoining the Gothic
Cathedral. A path leads west.
#226
You are on the floor of the Rainbow Room. In fact, you are spread
*ALL OVER* the floor of the Rainbow Room.
#227
You are in a dimly lit passage behind Thunder Hole. Etched into
the rock wall are the ominous words:
* "You are approaching the River Styx. *
* Laciate Ogni Speranza Voi Ch'Entrate." *
#228
You are at the River Styx, a narrow little stream cutting directly
across the passageway. The edge of the stream is littered with sticks
and other debris washed in by a recent rainfall. On the far side
of the river, the passage continues east.
#229
You're on the east side of the river's sticks.
#230
You are on a ledge at the northern end of a long N/S crawl. The
ledge is above a large number of sharp vertical limestone spires.
An attempt to climb down could be dangerous, if you get my *point*!
#231
You are very neatly skewered on the point of a sharp rock.
#232
You have poled your boat across the calm water.
#233
You have poled your boat across the dark water.
#234
You have poled your boat across the Blue Grotto.
#235
You're at Dante's Rest, on the north side of a yawning dark chasm.
A passage continues west along the chasm's edge.
#236
You are at the east end of a river bank path in Lost River Canyon.
#237
The staircase is now unclimbable.
#238
You're in the caretaker's pantry.
#239
You are on a small rise overlooking a beautiful bay. In the center
of the bay is the castle of the elves.
#240
You are on the highest pinnacle of the castle in the bay.
Steps lead down into the garden.
#241
You are in the outer courtyard of the garden of the elves.
Steps lead up to the tower, and to the west, separating you
from the inner courtyard, is a maze of hedges, living things,
but almost crystalline in their multicolored splendor.
#242
From the inside the maze looks like a kaleidoscope, with
swatches of color dancing as you move. In this part the colors
are produced by shining red berries on the branches.
#243
You are surrounded by a tall hedge with sharp iridescent leaves
and metallic orange flowers.
#244
You are in the center of the living maze. The plants here are
dormant this season, but still carry brilliant yellow leaves.
#245
Unlike the other areas of the hedge system, this area seems to
have no metallic gleam; nevertheless it is still breathtaking.
The trees and bushes are all variegated shades of green, the
evergreens being a rich dark shade while the seasonal bushes
are a lighter yellowish green, making a startling contrast.
#246
You are near the edge of the maze. You sample the blueberries
on the bushes. They are delicious.
#247
You are at the western end of the living maze. Beside the
shrubs forming the walls are tastefully planted beds of
violets and brilliant purple pansies.
To the west is the inner garden.
#248
You are in the inner garden of the elves. In the center is
a living tree, with shimmering silvery bark, glistening metallic
green leaves, and flowers ripe with nectar. As the nectar falls
to the ground it forms droplets of silver. Around the tree is
a hedge of briars which cannot be crossed. Unfortunately for
adventurers such as you, most of the nectar falls inside the hedge.
The exit is to the east.

514
commands/advent/advent2.txt Executable file
View file

@ -0,0 +1,514 @@
#1
You're at end of road again.
#2
You're at hill in road.
#3
You're inside building.
#4
You're in valley.
#5
You're in forest.
#6
You're in forest.
#7
You're at slit in streambed.
#8
You're outside grate.
#9
You're below the grate.
#10
You're in cobble crawl.
#11
You're in Debris Room.
#12
You are in an awkward sloping east/west canyon.
#13
You're in Bird Chamber.
#14
You're at top of small pit.
#15
You're in Hall of Mists.
#16
The crack is far too small for you to follow.
#17
You're on east bank of fissure.
#18
You're in Nugget of Gold Room.
#19
You're in Hall of Mt King.
#20
You are at the bottom of the pit with a broken neck.
#21
You didn't make it.
#22
The dome is unclimbable.
#23
You're at west end of Twopit Room.
#24
You're in east pit.
#25
You're in west pit.
#26
You clamber up the plant and scurry through the hole at the top.
#27
You are on the west side of the fissure in the Hall of Mists.
#28
You are in a low N/S passage at a hole in the floor. The hole goes
down to an E/W passage.
#29
You are in the South Side Chamber.
#30
You are in the West Side Chamber of the Hall of the Mountain King.
#31
<$$<
#32
You can't get by the snake.
#33
You're at "Y2".
#34
You are in a jumble of rock, with cracks everywhere.
#35
You're at window on pit.
#36
You're in dirty passage.
#37
You are on the brink of a small clean climbable pit.
#38
You are in the bottom of a small pit with a little stream.
#39
You're in dusty rock room.
#40
You have crawled through a very low wide passage parallel.
#41
You're at west end of Hall of Mists.
#42
You are in a maze of twisty little passages, all alike.
#43
You are in a maze of twisty little passages, all alike.
#44
You are in a maze of twisty little passages, all alike.
#45
You are in a maze of twisty little passages, all alike.
#46
Dead end.
#47
Dead end.
#48
Dead end.
#49
You are in a maze of twisty little passages, all alike.
#50
You are in a maze of twisty little passages, all alike.
#51
You are in a maze of twisty little passages, all alike.
#52
You are in a maze of twisty little passages, all alike.
#53
You are in a maze of twisty little passages, all alike.
#54
Dead end.
#55
You are in a maze of twisty little passages, all alike.
#56
Dead end.
#57
You're at brink of pit.
#58
Dead end.
#59
You have crawled through a very low wide passage.
#60
You're at east end of Long Hall.
#61
You're at west end of Long Hall.
#62
You are at a crossover of a high N/S passage and a low E/W one.
#63
Dead end.
#64
You're at Complex Junction.
#65
You are in Bedquilt.
#66
You're in Swiss Cheese Room.
#67
You're at east end of Twopit Room.
#68
You're in Slab Room.
#69
You are in a secret N/S canyon above a large room.
#70
You are in a secret N/S canyon above a sizable passage.
#71
You're at junction of three secret canyons.
#72
You are in a large low room. Crawls lead north, NE, and SW.
#73
Dead end crawl.
#74
You're in secret E/W canyon above tight canyon.
#75
You are at a wide place in a very tight N/S canyon.
#76
The canyon here becomes too tight to go further south.
#77
You are in a tall E/W canyon.
#78
The canyon runs into a mass of boulders -- dead end.
#79
The stream flows out through a pair of 1 foot diameter sewer pipes.
#80
You are in a maze of twisty little passages, all alike.
#81
Dead end.
#82
Dead end.
#83
You are in a maze of twisty little passages, all alike.
#84
You are in a maze of twisty little passages, all alike.
#85
Dead end.
#86
Dead end.
#87
You are in a maze of twisty little passages, all alike.
#88
You're in narrow corridor.
#89
There is nothing here to climb. Use "up" or "out" to leave the pit.
#90
You have climbed up the plant and out of the pit.
#91
You're at steep incline above large room.
#92
You're in Giant Room.
#93
The passage here is blocked by a recent cave-in.
#94
You are at one end of an immense north/south passage.
#95
You're in cavern with waterfall.
#96
You're in Soft Room.
#97
You're in Oriental Room.
#98
You're in Misty Cavern.
#99
You're in Alcove.
#100
You're in Plover Room.
#101
You're in Dark-Room.
#102
You're in Arched Hall.
#103
You're in Shell Room.
#104
You are in a long sloping corridor with ragged sharp walls.
#105
You are in a cul-de-sac about eight feet across.
#106
You're in Anteroom.
#107
You are in a maze of twisty little passages, all different.
#108
You're at Witt's End.
#109
You're in Mirror Canyon.
#110
You're at window on pit.
#111
You're at top of stalactite.
#112
You are in a little maze of twisting passages, all different.
#113
You're at Reservoir.
#114
Dead end.
#115
You're at NE end.
#116
You're at SW end.
#117
You're on SW side of chasm.
#118
You're in sloping corridor.
#119
You are in a secret canyon which exits to the north and east.
#120
You are in a secret canyon which exits to the north and east.
#121
You are in a secret canyon which exits to the north and east.
#122
You're on NE side of chasm.
#123
You're in corridor.
#124
You're at fork in path.
#125
You're at junction with warm walls.
#126
You're at breath-taking view.
#127
You're in Chamber of Boulders.
#128
You're in Limestone Passage.
#129
You're in front of Barren Room.
#130
You're in Barren Room.
#131
You are in a maze of twisting little passages, all different.
#132
You are in a little maze of twisty passages, all different.
#133
You are in a twisting maze of little passages, all different.
#134
You are in a twisting little maze of passages, all different.
#135
You are in a twisty little maze of passages, all different.
#136
You are in a twisty maze of little passages, all different.
#137
You are in a little twisty maze of passages, all different.
#138
You are in a maze of little twisting passages, all different.
#139
You are in a maze of little twisty passages, all different.
#140
Dead end.
#141
You're at Sword Point.
#142
You're at top of slide.
#143
You're at entrance to Throne Room.
#144
You're on east side of Throne Room.
#145
<$$<
#146
You're in forest.
#147
You're on grassy knoll.
#148
You are at the edge of a trackless salt marsh. Tall reeds obscure
the view.
#149
You're in salt marsh.
#150
You're in salty marsh.
#151
You are in salt marsh.
#152
Dead end.
#153
You're on sandy beach.
#154
You're at broken rocks.
#155
You're at Ocean Vista.
#156
You're at the bottom of the cliff.
#157
You're at Thunder Hole.
#158
You're at top of steps in back of Thunder Hole.
#159
You're in cramped chamber.
#160
You're at ledge by wrought-iron door.
#161
You feel dizzy...Everything around you is spinning, expanding,
growing larger.... Dear me! Is the cave bigger or are you smaller?
#162
You are again overcome by a sickening vertigo, but this time
everything around you is shrinking...Shrinking...
#163
You are again overcome by a sickening vertigo, but this time
everything is shrinking... I mean, you are growing. This is
terribly confusing!
#164
You feel dizzy...Everything around you is spinning, expanding,
growing larger....
#165
You're at the bottom of the cliff with a broken neck.
#166
You're at west wall of Blue Grotto.
#167
You're at underground sea.
#168
You're on east side of the Blue Grotto.
#169
You're in Bubble Chamber.
#170
You are in a windy tunnel between two large rooms.
#171
You're in Bat Cave.
#172
You are in a very tight N/S crack.
#173
You are in a very tight N/S crack.
#174
You're in the Cloakroom.
#175
You're in a room containing several small climbable pits.
#176
You are at the bottom of a small featureless pit.
#177
You are at a high hole in a rock wall.
#178
The NE passage is blocked by a recent cave-in.
#179
You are in a sloping muddy defile, next to a tumbling brook.
#180
You're at Tongue of Rock.
#181
The dog won't let you pass.
#182
You're in the Upper Passage, a long level E/W tunnel.
#183
You're in Star Chamber.
#184
You are at an elbow in a winding E/W passage.
#185
Dead end.
#186
You're at the intersection of two long tunnels.
#187
You're in a long narrow east-west passage.
#188
You're in Rotunda.
#189
You're in phone booth.
#190
You're at Devil's Chair.
#191
You're in a dead-end crack.
#192
You're on gravel beach.
#193
You're in Flower Room.
#194
You are at east end of short E/W corridor.
#195
You are at east end of short E/W corridor.
#196
You're in Arched Hall.
#197
You're in the Vestibule, a short east-west passage between two rooms.
#198
You're in the Fairy Grotto.
#199
You have approached the lower end of a steep passage.
#200
You're in the Crystal Palace.
#201
You are following a yellow sandstone path.
#202
You're in the Rainbow Room.
#203
You're in a steeply sloping passage. It is very cold here.
#204
You're in the Hall of Ice.
#205
You are over the Rainbow (Room).
#206
You're in Green Lake Room.
#207
You're in red rock crawl.
#208
You're on south side of Lost River Canyon.
#209
You're at end of Lost River Canyon.
#210
You're at niche in ledge above Lost River.
#211
A very narrow and treacherous ledge.
#212
You're in phone booth.
#213
You're at the east end of a level passage at a hole in the floor.
#214
You're in dark cove.
#215
You're in dry basin.
#216
You're in old spillway.
#217
You're in the Winery.
#218
You're at limestone pinnacles.
#219
You're in Gothic Cathedral.
#220
You're at the east portal of the Gothic Cathedral.
#221
You're at the west portal of the Gothic Cathedral.
#222
You are at the foot of the Altar, an immense, broad stalagmite.
#223
You're on top of stalagmite.
#224
You're in the Crypt.
#225
You're in Gothic Chapel.
#226
You are on the floor of the Rainbow Room.
#227
You are at approach to River Styx.
#228
You're at the River Styx.
#229
You're on the east side of the river's sticks.
#230
You're on ledge above limestone pinnacles.
#231
You are very neatly skewered on the point of a sharp rock.
#232
You have poled your boat across the calm water.
#233
You have poled your boat across the dark water.
#234
You have poled your boat across the Blue Grotto.
#235
You're at Dante's Rest.
#236
You're at east end of Lost River Canyon.
#237
The staircase is now unclimbable.
#238
You're in the caretaker's pantry.
#239
You're on a small rise over the bay.
#240
You are on the highest pinnacle of the castle in the bay.
Steps lead down into the garden.
#241
You are in the outer courtyard of the elves.
#242
You are in the living maze. There are red berries here.
#243
You are surrounded by a tall hedge with sharp iridescent leaves
and metallic orange flowers.
#244
You are in the center of the living maze. The plants here are
dormant this season, but still carry brilliant yellow leaves.
#245
Unlike the other areas of the hedge system, this area seems to
have no metallic gleam; nevertheless it is still breathtaking.
The trees and bushes are all variegated shades of green, the
evergreens being a rich dark shade while the seasonal bushes
are a lighter yellowish green, making a startling contrast.
#246
You are near the edge of the maze. You sample the blueberries
on the bushes. They are delicious.
#247
You are at the western end of the living maze. Beside the
shrubs forming the walls are tastefully planted beds of
violets and brilliant purple pansies.
To the west is the inner garden.
#248
You're in the inner courtyard of the elves.

539
commands/advent/advent3.txt Executable file
View file

@ -0,0 +1,539 @@
#1
#2
/Brass lantern
/There is a shiny brass lamp nearby.
/There is a lamp shining nearby.
/
#3
/*Grate
/The grate is locked.
/The grate is open.
/
#4
/Wicker cage
/There is a small wicker cage discarded nearby.
/
#5
/Black rod
/A three foot black rod with a rusty star on an end lies nearby.
/
#6
/Black rod
/A three foot black rod with a rusty mark on an end lies nearby.
/
#7
/*Steps
/Rough stone steps lead down the pit.
/Rough stone steps lead up the dome.
/
#8
#9
/Wooden pole
/A wooden pole is lying nearby.
/A wooden pole has been stuck in the mud here.
/
#10
/Velvet pillow
/A small velvet pillow lies on the floor.
/
#11
/*Snake
/A huge green fierce snake bars the way!
/<$$< (Chased away)
/
#12
/*Fissure
/<$$<
/A crystal bridge now spans the fissure.
/The crystal bridge has vanished!
/
#13
/*Stone tablet
/A massive stone tablet imbedded in the wall reads:
"Congratulations on bringing light into the Dark-Room!"
/
#14
/Giant clam >grunt!<
/There is an enormous clam here with its shell tightly closed.
/
#15
/Giant oyster >groan!<
/There is an enormous oyster here with its shell tightly closed.
/Interesting. There seems to be something written on the underside of
the oyster.
/
#16
/"Spelunker Today"
/There are a few recent issues of "Spelunker Today" magazine here.
/
#17
#18
#19
/Tasty food
/There is food here.
/
#20
/Small bottle
/There is a small bottle here.
/There is an empty bottle here.
/There is a small bottle here.
/There is a broken bottle here.
/There is a small bottle here.
/
#21
/*Chasm - troll bridge
/A rickety wooden bridge extends across the chasm, vanishing into the
mist. A sign posted on the bridge reads, "Stop! Pay troll!"
/The wreckage of a bridge (and a dead bear) can be seen at the bottom
of the chasm.
/
#22
/*Chasm2 & decrepit natural bridge
/A decrepit natural bridge spans the chasm. A message scrawled into
the rock wall reads: "Bridge out of repair. Maximum load: 35 Foonts."
/The remnants of a natural bridge partially overhang the chasm.
/
#23
/*Mirror
/<$$<
/
#24
/*plant
/There is a tiny little plant in the pit, murmuring "Water, water, ..."
/The plant spurts into furious growth for a few seconds.
/There is a 12-foot-tall beanstalk stretching up out of the pit,
bellowing "Water!! Water!!"
/The plant grows explosively, almost filling the bottom of the pit.
/There is a gigantic beanstalk stretching all the way up to the hole.
/You've over-watered the plant! It's shriveling up! It's, it's...
/
#25
/*Phony plant (seen in twopit room only when tall enough)
/<$$<
/The top of a 12-foot-tall beanstalk is poking out of the west pit.
/There is a huge beanstalk growing out of the west pit up to the hole.
/
#26
/*Stalactite
/<$$<
/
#27
/*shadowy figure
/The shadowy figure seems to be trying to attract your attention.
/
#28
/Dwarf's axe
/There is a little axe here.
/There is a little axe lying beside the bear.
/There is a little axe lying beside the Wumpus.
/There is a little axe lying beside the dog.
/
#29
/*Cave drawings
/<$$<
/
#30
/*pirate
/<$$<
/
#31
/*dragon
/A huge green fierce dragon bars the way!
/Congratulations! You have just vanquished a dragon with your bare
hands! (Unbelievable, isn't it?)
/The body of a huge green dead dragon is lying off to one side.
/
#32
#33
/*Troll
/A burly troll stands by the bridge and insists you throw him a
treasure before you may cross.
/The troll steps out from beneath the bridge and blocks your way.
/<$$< (Chased away)
/
#34
/*phony troll
/The troll is nowhere to be seen.
/
#35
/<$$< (Bear uses rtext 141)
/There is a ferocious cave bear eying you from the far end of the room!
/There is a gentle cave bear sitting placidly in one corner.
/There is a contented-looking bear wandering about nearby.
/<$$< (Dead)
/
#36
/*Message in second maze
/There is a message scrawled in the dust in a flowery script, reading:
"This is not the maze where the pirate leaves his treasure chest."
/
#37
/*Volcano and/or geyser
/<$$<
/
#38
/*Vending machine
/There is a massive vending machine here. The instructions on it
read: "Insert coins to receive fresh batteries."
/There is a massive vending machine here.
/
#39
/Batteries
/There are fresh batteries here.
/Some worn-out batteries have been discarded nearby.
/Some worn-out batteries have been discarded nearby.
/
#40
/*Carpet and/or moss
/<$$<
/
#41
/*Rusty door
/The way north is barred by a massive, rusty, iron door.
/The way north leads through a massive, rusty, iron door.
/
#42
/*Tiny door
/The only way past the wall is through a tiny locked door.
/The only way past the wall is through a tiny open door.
/
#43
/*Tiny door-2
/The door is locked.
/The door is open.
/
#44
/*Phone booth door
/<$$<
/
#45
#46
/Beautiful flowers
/There are some beautiful flowers here!
/On the other side of the room a swarm of bees eagerly buzzes over
a bunch of fresh flowers.
/
#47
/Silken cloak
/There is a silken cloak here!
/<$$< (wearing cloak)
/A lovely silken cloak lies partially buried under a pile of
loose rocks.
/
#48
/Wooden boat
/There is a small wooden boat here.
/You are in a wooden boat.
/
#49
/*Sticks at Styx
/<$$<
/
#50
/Large gold nugget
/There is a large sparkling nugget of gold here!
/
#51
/Several diamonds
/There are diamonds here!
/
#52
/Silver horn
/There is a silver horn here!
/
#53
/Precious jewelry
/There is precious jewelry here!
/<$$< (wearing jewelry)
/
#54
/Rare coins
/There are many coins here!
/
#55
/Treasure chest
/The pirate's treasure chest is here!
/
#56
/Golden eggs
/There is a large nest here, full of golden eggs!
/The nest of golden eggs has vanished!
/Done!
/
#57
/Jeweled trident
/There is a jewel-encrusted trident here!
/
#58
/Ming vase
/There is a delicate, precious, ming vase here!
/The vase is now resting, delicately, on a velvet pillow.
/The floor is littered with worthless shards of pottery.
/The ming vase drops with a delicate crash.
/
#59
/Egg-sized emerald
/There is an emerald here the size of a plover's egg!
/
#60
/Platinum pyramid
/There is a platinum pyramid here, 8 inches on a side!
/
#61
/Glistening pearl
/Off to one side lies a glistening pearl!
/
#62
/Persian rug
/There is a persian rug spread out on the floor!
/The dragon is sprawled out on a persian rug!!
/
#63
/Rare spices
/There are rare spices here!
/
#64
/Golden chain
/There is a golden chain lying in a heap on the floor!
/The bear is locked to the wall with a golden chain!
/There is a golden chain locked to the wall!
/
#65
/Gleaming sword
/There is a gleaming sword here!
/A gleaming sword is stuck into the anvil!
/You grasp the sword's handle and give a mighty heave, but with a
loud clang the sword blade shatters into several fragments.
/Rusty shards of a elven sword lie scattered about.
/A very clean sword is stuck into the anvil!
/An oily sword is stuck into the anvil.
/
#66
/Elfin crown
/An ancient crown of elfin kings lies here!
/<$$< (wearing crown)
/
#67
/Ruby slippers
/There is a pair of ruby slippers here.
/<$$< (wearing slippers)
/There is a pair of ruby slippers here.
/
#68
/Delicate lyre
/There is a delicate lyre here!
/
#69
/Star sapphire
/There is a star sapphire here!
/
#70
/Holy Grail
/There is an ornate silver chalice here!
/
#71
/Oaken cask
/There is an oaken cask here.
/There is an empty oaken cask here.
/There is an oaken cask here.
/<$$< (Unused)
/There is an oaken cask here.
/
#72
/Golden ring
/There is a small gold ring here.
/<$$< (wearing ring)
/On the Wumpus' finger is a small gold ring.
/
#73
/Four-leafed clover
/There is a four-leafed clover here!
/<$$< (wearing clover)
/
#74
/Gold tree
/There is a gold statue of a tree here.
/
#75
/Silver droplet
/There is a single droplet of silver on the ground here.
/
#76
#77
#78
#79
#80
#81
/Clear water
/
#82
/Cool water
/
#83
/Thick, black oil
/
#84
/Thick, black oil
/
#85
/Vintage wine
/
#86
/Vintage wine
/
#87
/*Bumblebees
/<$$<
/Some bumblebees are swarming around a bunch of fresh flowers.
/
#88
/*Hollow wall
/Your footsteps echo hollowly throughout the chamber.
/<$$<
/
#89
/*Wall with safe
/A steel safe is embedded in the wall.
/
#90
/Tiny brass key
/There is a tiny brass key here.
/There is a tiny brass key on the shelf.
/
#91
/*Anvil
/<$$<
/
#92
/*rocks on cloak
/<$$< (ON CLOAK)
/<$$< (AFTER ROCK SLIDE)
/
#93
/*telephone booth
/The telephone booth is empty.
The phone is ringing.
/The phone booth is occupied by a gnome. He is talking excitedly
to someone at the other end.
/The telephone booth is empty.
/<$$<
/
#94
/*Telephone
/The phone is ringing.
/The telephone is out of order.
/The telephone is out of order. It is badly dented.
/<$$<
/
#95
/Lead slugs
/There are some lead slugs here!
/
#96
/Sweet honeycomb
/There is a sweet honeycomb here!
/
#97
/*Beehive
/There is an active beehive nearby. The bees hum protectively
around the hive.
/There is an empty beehive nearby.
/
#98
/*Black dog
/A hideous black dog bares his teeth and growls at your approach.
/Nearby, a large black dog is in a deep slumber.
/
#99
/*Dreaded Wumpus
/In the corner, a Wumpus is sleeping peacefully.
/A sleepy Wumpus is ambling towards you. He wants to invite you to
dinner. He wants you to *be* the dinner!
/The Wumpus is still on your trail! And he's getting closer!!
/The Wumpus is only a few steps behind you! All this exercise is
making him veerrrrry hungry!
/The Wumpus almost has you in his grasp! You can feel his hot breath
on your neck!
/"Chomp, chomp." Crunch! Chew! Slurp! Smack! Yum!!!
/Nearby is the smashed body of a defunct Wumpus.
/
#100
#101
/Little bird in cage
/A cheerful little bird is sitting here singing.
/There is a little bird in the cage.
/
#102
/Set of keys
/There are some keys on the ground here.
/
#103
/*Fountain
/There is a fountain of sparkling vintage wine here!
/
#104
/*Bats & guano in bat-cave
/<$$<
/
#105
/*gnome in phone booth
/<$$<
/
#106
/Colored mushrooms
/There are some oddly-colored mushrooms here.
/
#107
/Tiny cakes
/There are some tiny cakes on the shelf.
/
#108
/Leather Sack
/There is a leather sack here.
/
#109
#110
/Rare book
/There is a dusty, leather-bound volume here.
/
#111
/Rare book
/There is a dusty, leather-bound volume here.
/
#112
/Steel wall-safe
/The safe door is locked.
/The safe door is open.
/
#113
/Faded poster
/Taped to the wall is a faded poster.
/There is a faded poster here.
/
#114
/Whiskbroom
/There is a small whiskbroom here.
/
#115
/*Carving on dusty rocks
/<$$<
/<$$<
/
#116
/*Billboard
/
/
#117
#118
/Small metal canister
/There is a heavy, grey, metal canister here.
/
#119
/Glowing stone
/Nearby, a strange, greenish stone is glowing brightly.
/
#120
/Quartz sphere
/There is a polished sphere of pure quartz here!
/

1068
commands/advent/advent4.txt Executable file

File diff suppressed because it is too large Load diff

141
commands/advent/database.c Executable file
View file

@ -0,0 +1,141 @@
/* program DATABASE.C */
#include <string.h>
#include <stdio.h>
#include "advent.h"
#include "advdec.h"
#include "advtext.h"
static char oline[256];
_PROTOTYPE(void rdupto, (FILE *, int, int, char *));
_PROTOTYPE(void rdskip, (FILE *, int, int));
/*
Function to scan a file up to a specified
point and either print or return a string.
*/
void rdupto(fdi, uptoc, print, string)
FILE *fdi;
int uptoc, print;
char *string;
{
int c, i;
static _CONST unsigned char key[4] = {'c' | 0x80, 'L' | 0x80,
'y' | 0x80, 'D' | 0x80};
i = 1;
while ((c = getc(fdi)) != uptoc && c != EOF) {
if (c == '\n')
i = 1;
if (c >= 0x80)
c ^= key[i++ & 3];
if (c == '\r')
continue;
if (print)
putchar(c);
else
*string++ = (char) c;
}
if (!print)
*string = '\0';
return;
}
/*
Function to read a file skipping
a given character a specified number
of times, with or without repositioning
the file.
*/
void rdskip(fdi, skipc, n)
FILE *fdi;
int skipc, n;
{
int c;
while (n--)
while ((c = getc(fdi)) != skipc)
if (c == EOF)
bug(32);
return;
}
/*
Routine to request a yes or no answer to a question.
*/
boolean yes(msg1, msg2, msg3)
int msg1, msg2, msg3;
{
char answer[INPUTBUFLEN];
if (msg1)
rspeak(msg1);
do {
switch (*ask("\n> ", answer, sizeof(answer))) {
case 'n':
case 'N':
if (msg3)
rspeak(msg3);
return (FALSE);
case 'y':
case 'Y':
if (msg2)
rspeak(msg2);
return (TRUE);
default:
fputs("Please answer Y (yes) or N (no).", stdout);
}
} while (TRUE);
}
/*
Print a location description from "advent4.txt"
*/
void rspeak(msg)
int msg;
{
if (msg == 54)
printf("ok.\n");
else {
fseek(fd4, idx4[msg - 1], 0);
rdupto(fd4, '#', 1, 0);
}
return;
}
/*
Print an item message for a given state from "advent3.txt"
*/
void pspeak(item, state)
int item, state;
{
fseek(fd3, idx3[item - 1], 0);
rdskip(fd3, '/', state + 2);
rdupto(fd3, '/', FALSE, oline);
if (strncmp(oline, "<$$<", 4) != 0)
printf("%s", oline);
return;
}
/*
Print a long location description from "advent1.txt"
*/
void desclg(loc)
int loc;
{
fseek(fd1, idx1[loc - 1], 0);
rdupto(fd1, '#', 1, 0);
return;
}
/*
Print a short location description from "advent2.txt"
*/
void descsh(loc)
int loc;
{
fseek(fd2, idx2[loc - 1], 0);
rdupto(fd2, '#', 1, 0);
return;
}

676
commands/advent/english.c Executable file
View file

@ -0,0 +1,676 @@
/* program ENGLISH.C */
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include "advent.h"
#include "advdec.h"
#define ALL 109
#define ENTER 3
#define CRAWL 17
#define JUMP 39
#define CLIMB 56
#define XYZZY 62
#define PLUGH 65
#define PLOVER 71
#define PHUCE 82
_PROTOTYPE(static void getwords, (void));
_PROTOTYPE(static void clrlin, (void));
_PROTOTYPE(static void doobj, (int *));
_PROTOTYPE(static boolean doiobj, (void));
_PROTOTYPE(static boolean do_scoop_up, (void));
_PROTOTYPE(static boolean check_next, (void));
static char buffer[INPUTBUFLEN] = {'\0', '\0', '\0', '\0'};
static char *txt[MAXWORDS] = {buffer, buffer, buffer, buffer};
static char *cindex = buffer;
static boolean pflag;
static int vrbkey, words[MAXWORDS] = {0, 0, 0, 0}, word, wdx = 0;
static int takdir[20] = {2, 6, 9, 10, 11, 13, 14, 17, 23, 25,
33, 34, 36, 37, 39, 78, 79, 80, 89, -1};
static int vkey[60] = {
0, 199, 9, 0, 130, 0, 197, 0, 0, 243,
0, 0, 89, 140, 0, 5, 0, 227, 0, 0,
0, 31, 42, 0, 0, 0, 0, 172, 1, 0,
0, 0, 254, 0, 69, 0, 0, 92, 0, 0,
138, 137, 149, 239, 45, 74, 183, 0, 0, 112,
241, 0, 114, 0, 30, 0, 0, 0, 0, 0
};
static int ptab[260] = {
0, 3028, 3065, 3009, -3005, 5071, 5070, 5058, -5020, 19055,
19108, 19038, 19020, 19071, 19070, 19058, 19004, 19048, 19091, 19094,
19112, 19002, 19118, 2062, 2066, 2047, 2067, 2053, 2065, -2010,
-3114, 4034, 4011, 4101, 4035, 4099, 4098, 4017, 4104, 4014,
4015, -4087, 3083, 3085, -3081, 5055, 5108, 5020, 5071, 5070,
5058, 5004, 5048, 5091, 5112, 5099, 5118, 19055, 19108, 19020,
19071, 19070, 19058, 19004, 19048, 19091, 19112, 19099,-19118, 3028,
3065, 3009, 3005, -3018, 19055, 19108, 19038, 19020, 19071, 19070,
19058, 19004, 19004, 19048, 19091, 19094, 19112, 19002,-19118, 3028,
3065, -3018, 19055, 19108, 19038, 19020, 19071, 19070, 19058, 19004,
19048, 19091, 19094, 19112, 19118, 2062, 2066, 2047, 2067, 2053,
2065, -2010, 3102, -3090, 19055, 19108, 19020, 19071, 19070, 19058,
19004, 19048, 19091, 19014, 19015, 19112, 19118, 19120, 19120, -9999,
3090, 3102, 3028, 3057, 3065, 3009, -3005,-29999, 2052, -2068,
2024, 2065, 2091, 2042, 2073, 5071, 5070, 5058, -5020, 30999,
2062, 2066, 2047, 2067, 2053, 2065, 2010, 2073, 19055, 19108,
19038, 19020, 19071, 19070, 19058, 19004, 19048, 19091, 19094, 19112,
19002,-19118, 2014, 2015, 2013, 2999, 5014, 5015, 5013, 5999,
5110, 5113, -5999, 5055, 5108, 5020, 5071, 5070, 5058, 5004,
5048, 5091, 5014, 5015, 5112, 5099, -5118, 3102, -3090, 6066,
6047, 6067, 6053, 6072, 6073, 5055, 5108, 5020, 5071, 5070,
5004, 5004, 5048, 5091, 5112, 5099, 5118, 19055, 19108, 19020,
19071, 19070, 19058, 19004, 19048, 19091,-19118, 4034, 4011, 4101,
4035, 4099, 4098, 4017, 4104, 4027, 4087, 9999,-30999, 2002,
-6002, 3102, -3090, 9999, 4034, 4011, 4101, 4035, 4099, 4087,
4098, 4017, 4104, -4027, -5999, 0, 0, 0, 0, 0,
};
static int adjkey[40] = {
0, 15, 38, 64, 4, 63, 1, 61, 62, 67,
9, 27, 53, 46, 47, 60, 31, 39, 40, 6,
43, 26, 32, 28, 34, 50, 49, 45, 44, 10,
20, 25, 21, 36, 37, 30, 33, 0, 0, 0
};
static int adjtab[70] = {
0, 5, 98, -83, 2, -90, 66, 41, -90, -39,
41, 14, 15, 50, -11, 50, 64, 56, 72, -74,
-19, 119, 59, 73, -118, -119, -70, -41, 95, -118,
-118, -58, -71, -120, 110, -108, -120, -73, -62, -60,
110, 54, -63, -67, -41, -27, -47, 52, -75, -69,
65, 112, -3, 41, 72, 90, 20, 101, 107, -118,
-55, -10, -38, -4, 48, 9, -71, -39, 0, 0
};
/*
Analyze a two word sentence
*/
int english()
{
char *ch_ptr, *word1, *word2;
int type, val, type2, val2, adj, k, kk;
static int iwest = 0;
if (!(words[++wdx])) {
getwords();
wdx = 0;
}
pflag = FALSE;
word = words[wdx];
if (word < 0) { /* check first word */
printf("I didn't understand the word \"%s\"\n", txt[wdx]);
words[wdx+1] = 0;
return (FALSE); /* didn't know it */
}
type2 = val2 = -1;
type = CLASS(word);
clrlin();
val = VAL(word);
if (words[wdx + 1] && CLASS(words[wdx + 1]) != CONJUNCTION) {
/* 'SAY' or 'CALL'. If no next word, pass on to higher powers. */
if (type == ACTION && (val == SAY || val == YELL)) {
word = words[++wdx];
if (!(word == XYZZY || word == PLUGH
|| word == PLOVER || word == PHUCE)) {
if (val == SAY)
printf("Okay, \"%s\".\n", txt[wdx]);
else {
for (ch_ptr = txt[wdx]; *ch_ptr; ch_ptr++)
if (islower(*ch_ptr))
*ch_ptr = toupper(*ch_ptr);
printf("Okay, \"%s\"!!!!!\n", txt[wdx]);
}
return (FALSE);
}
} else {
word1 = txt[wdx];
word2 = txt[wdx + 1];
/* Special stuff for 'ENTER'. Can't go into water. 'ENTER
BOAT' means 'TAKE BOAT' */
if (word == ENTER) {
if (CLASS(words[wdx + 1]) == NOUN && VAL(words[wdx + 1]) == BOAT)
word = TAKE + 2000;
else if ((strcmp(word2, "stream") == 0)
|| (strcmp(word2, "water") == 0)
|| (strcmp(word2, "reservoir") == 0)
|| (strcmp(word2, "ocean") == 0)
|| (strcmp(word2, "sea") == 0)
|| (strcmp(word2, "pool") == 0)) {
rspeak(liqloc(g.loc) == WATER ? 70 : 43);
wdx++;
return (FALSE);
}
} else {
type2 = CLASS(words[wdx + 1]);
val2 = VAL(words[wdx + 1]);
/* 'LEAVE' is motion verb, unsless leaving an object.
E.G., 'LEAVE BOAT' or 'LEAVE BOTTLE'. BUt make sure
to leave ('DROP') only totable objects. */
if (strcmp(word1, "leave") == 0 && type2 == NOUN) {
if (!hinged(val2) || g.fixed[val2])
word = LEAVE + 2000;
/* IF 'LIGHT LAMP', Light must be taken as an
action verb, not a noun. */
} else if (strcmp(word1, "light") == 0
&& VAL(words[wdx + 1]) == LAMP) {
word = ON + 2000;
/* 'WATER PLANT' becomes 'POUR WATER', If we are at
plant. 'OIL DOOR' becomes 'POUR OIL', etc., etc. */
} else if ((strcmp(word1, "water") == 0 || strcmp(word1, "oil") == 0)
&& (strcmp(word2, "plant") == 0 || strcmp(word2, "door") == 0
|| strcmp(word2, "sword") == 0 || strcmp(word2, "anvil") == 0)
&& at(val2)) {
words[wdx + 1] = word;
txt[wdx + 1] = txt[wdx];
word = POUR + 2000;
}
}
}
}
/* This is the 'inner' loop. Dispatching of all word in a clause
after the first comes through here. */
do {
switch (CLASS(word)) {
case MOTION:
{
boolean do_part2;
int i;
do_part2 = FALSE;
type = CLASS(verbs[vrbx]);
val = VAL(verbs[vrbx]);
if (!vrbx)
do_part2 = TRUE;
else {
if (type > ACTION) {
rspeak(confuz());
return (FALSE);
}
}
if (type == ACTION) {
if (val == GO)
do_part2 = TRUE;
else {
if (val == TAKE) {
for (i = 0; i < 20; i++)
if (takdir[i] == val)
do_part2 = TRUE;
}
if (!do_part2) {
word = vocab(txt[wdx], 1);
if (word)
words[wdx--] = word;
}
}
} else if (type != CRAWL && type != JUMP
&& type != CLIMB)
do_part2 = TRUE;
if (do_part2) {
verbs[1] = word;
vrbx = 1;
if (strcmp(txt[wdx], "west") == 0) {
iwest++;
if (iwest == 10)
rspeak(17);
}
}
break;
}
case NOUN:
if (pflag) {
if (!doiobj())
return (FALSE);
} else {
word = VAL(word);
if (word == ALL) {
if (!do_scoop_up())
return (FALSE);
} else {
doobj(&word);
if (word > 0) {
objs[++objx] = word;
otxt[objx] = txt[wdx];
} else {
clrlin();
pflag = FALSE;
wdx++;
while (words[wdx]) {
if (CLASS(words[wdx]) == CONJUNCTION)
break;
wdx++;
}
if (words[wdx] == 0)
return (FALSE);
}
}
}
break;
case ACTION:
if (vrbx == 0)
vrbx++;
else {
if (VAL(verbs[vrbx]) == TAKE) {
val = VAL(word);
if (val == DRINK || val == INVENTORY
|| val == SCORE || val == NOTHING
|| val == LOOK);
else if (val == GO && (
strcmp(txt[wdx], "walk") == 0
|| strcmp(txt[wdx], "run") == 0
|| strcmp(txt[wdx], "hike") == 0));
else {
rspeak(confuz());
return (FALSE);
}
} else if (objx || CLASS(words[wdx - 1]) == CONJUNCTION) {
rspeak(confuz());
return (FALSE);
}
}
verbs[vrbx] = word;
vtxt[vrbx] = txt[wdx];
break;
case MISC:
if (vrbx) {
rspeak(confuz());
return (FALSE);
}
verbs[1] = word;
vrbx = 1;
break;
case PREPOSITION:
if (CLASS(verbs[vrbx]) != ACTION || iobx) {
rspeak(confuz());
return (FALSE);
}
vrbkey = vkey[VAL(verbs[vrbx])];
if (!vrbkey) {
rspeak(confuz());
return (FALSE);
}
prep = VAL(word);
pflag = TRUE;
break;
case ADJACTIVE:
/* Adjective handler. Scarf the next word, make sure it is
a valid object for this object. Then call getobj to see
if it is really there, Then link into object code. */
adj = VAL(word);
if (!check_next())
return (FALSE);
else if (CLASS(word) == CONJUNCTION) {
printf("%s what?\n", txt[wdx - 1]);
return (FALSE);
} else {
if (CLASS(word) != NOUN)
word = vocab(txt[wdx], NOUN);
if (word == -1 || CLASS(word) != NOUN || VAL(word) == ALL) {
rspeak(confuz());
return (FALSE);
}
words[wdx] = word;
kk = VAL(word);
for (k = adjkey[adj]; adjtab[k] >= 0; k++) {
if (kk == abs(adjtab[k]))
break;
}
if (adjtab[k] < 0) {
rspeak(confuz());
return (FALSE);
}
}
break;
case CONJUNCTION:
if (!check_next())
return (FALSE);
switch (CLASS(word)) {
case MOTION:
case ACTION:
case MISC:
words[wdx--] = 0;
break;
case NOUN:
case ADJACTIVE:
break;
case PREPOSITION:
case CONJUNCTION:
rspeak(confuz());
return (FALSE);
default:
bug(33);
}
break;
default:
bug(33);
}
word = words[++wdx];
if (word < 0) {
if (pct(50))
printf("I don't understand the word %s?\n", txt[wdx]);
else
printf("Mumble ? %s\n", txt[wdx]);
words[wdx+1] = 0;
return (FALSE);
}
type = CLASS(word);
if (type == NOUN) {
/* It's not the first: Make sure he included a comma or
'and'. Differenctiate between direct & indirect objects.
Check for special case of multiple ofjects: 'feed bear
honey' or 'throw troll nugget'. */
if ((pflag ? iobx : objx)
&& CLASS(words[wdx - 1]) != CONJUNCTION) {
val = VAL(verbs[vrbx]);
if (!living(objs[objx]) || (val != THROW && val != FEED)) {
rspeak(confuz());
return (FALSE);
}
iobx++;
iobjs[iobx] = objs[objx];
objs[objx] = 0;
objx++;
}
}
} while (word);
if (verbs[1] == 0) {
if (objs[1] == 0) {
rspeak(confuz());
clrlin();
} else if (objs[2])
printf("What do you want to do with them?\n");
else
printf("What do you want to do with %s?\n", otxt[1]);
return (FALSE);
} else if (objx > 1 && iobx > 1) {
rspeak(confuz());
return (FALSE);
}
return (TRUE);
}
/*
retrieve input line (max INPUTBUFLEN chars), convert to lower case
& rescan for first two words (max. WORDSIZE-1 chars).
*/
static void getwords()
{
static int wdx = 0;
int i, term_loc;
char terminator;
if (*cindex == '\0') {
while (!*ask("\n> ", buffer, sizeof(buffer))) ;
for (cindex = buffer; *cindex; cindex++)
if (isupper(*cindex))
*cindex = tolower(*cindex);
cindex = buffer;
}
wdx = 0;
buffer[sizeof(buffer)-1] = '\0';
for (i = 0; i < MAXWORDS; i++) {
txt[i] = &buffer[sizeof(buffer)-1];
words[i] = 0;
}
do {
while (*cindex == ' ')
cindex++;
txt[wdx] = cindex;
term_loc = strcspn(cindex, " ,.;\n");
cindex += term_loc;
terminator = *cindex;
*cindex++ = '\0';
if ((strcmp(txt[wdx], "a") != 0)
&& (strcmp(txt[wdx], "the") != 0)
&& (strcmp(txt[wdx], "an") != 0)) {
words[wdx] = vocab(txt[wdx], 0);
wdx++;
}
if (terminator == ',') {
txt[wdx] = "and";
words[wdx] = vocab(txt[wdx], 0);
wdx++;
}
}
while ((terminator != ';') && (terminator != '.')
&& (terminator != '\0') && (terminator != '\n'));
if (terminator == '\0')
cindex--;
return;
}
/* CLRIN, clears out all surrent syntax args in preparation for
* new input line
*/
static void clrlin()
{
int i;
for (i = 0; i < MAXWORDS; i++) {
verbs[i] = 0;
vtxt[i] = &buffer[sizeof(buffer)-1];
}
for (i = 0; i < MAXITEMS; i++) {
objs[i] = 0;
otxt[i] = &buffer[sizeof(buffer)-1];
iobjs[i] = 0;
iotxt[i] = &buffer[sizeof(buffer)-1];
}
vrbx = 0;
objx = 0;
iobx = 0;
prep = 0;
}
/*
Routine to process an object.
*/
static void doobj(object)
int *object;
{
int msg;
if (holding(*object))
return;
if (blind()) {
printf("I see no %s here.\n", txt[wdx]);
*object = 0;
return;
}
/* Is object here? if so, transitive */
if (g.fixed[*object] == g.loc || athand(*object))
return;
else if (here(*object)) {
msg = plural(*object) ? 373 : 335;
*object = 0;
rspeak(msg);
}
/* Did he give grate as destination? */
else if (*object == GRATE) {
if (g.loc == 1 || g.loc == 4 || g.loc == 7) {
verbs[1] = DEPRESSION;
vrbx = 1;
return;
} else if (g.loc > 9 && g.loc < 15) {
verbs[1] = ENTRANCE;
vrbx = 1;
return;
}
}
/* Is it a dwarf he is after? */
else if (dcheck() && g.dflag >= 2) {
*object = DWARF;
}
/* Is he trying to get/use a liquid? */
else if (liqloc(g.loc) == *object
|| (liq(BOTTLE) == *object && athand(BOTTLE))
|| (liq(CASK) == *object && athand(CASK)));
else if (*object == PLANT && at(PLANT2) &&
g.prop[PLANT2] == 0) {
*object = PLANT2;
} else if (*object == ROCKS && at(CARVNG)) {
*object = CARVNG;
}
/* Is he trying to grab a knife? */
else if (*object == KNIFE && g.knfloc == g.loc) {
rspeak(116);
g.knfloc = -1;
}
/* Is he trying to get at dynamite? */
else if (*object == ROD && athand(ROD2)) {
*object = ROD2;
} else if (*object == DOOR && (at(SAFE) || at(TDOOR)
|| at(TDOOR2) || at(PDOOR))) {
if (at(TDOOR2))
*object = TDOOR2;
else if (at(PDOOR))
*object = PDOOR;
else if (at(SAFE))
*object = SAFE;
else
*object = TDOOR;
} else if (*object == BOOK && athand(BOOK2)) {
*object = BOOK2;
} else if (!(verbs[vrbx] == FIND || verbs[vrbx] == INVENTORY)) {
*object = 0;
printf("I see no %s here.\n", txt[wdx]);
}
return;
}
static boolean doiobj()
{
char dk[INPUTBUFLEN], dkk[INPUTBUFLEN];
int kk;
boolean ok;
/* checks object is valid for this preposition */
ok = TRUE;
word = VAL(word);
if (word != ALL) {
doobj(&word);
if (word > 0) {
iobjs[++iobx] = word;
iotxt[iobx] = txt[wdx];
} else
ok = FALSE;
}
kk = abs(ptab[vrbkey]) / 1000;
if (kk == prep) {
/* preprosition is valid with this verb now check object of
preprosition */
if (word == 0 || CLASS(word) == CONJUNCTION) {
/* no object following prepresition: check special cases */
pflag = FALSE;
strcpy(dk, txt[--wdx]);
strcpy(dkk, vtxt[vrbx]);
ok = FALSE;
if ((strcmp(dk, "on") == 0
|| strcmp(dk, "off") == 0)
&& (strcmp(dkk, "turn") == 0
|| objs[objx] == LAMP))
ok = TRUE;
if (strcmp(dkk, "take") == 0
|| strcmp(dkk, "put") == 0)
ok = TRUE;
if (strcmp(dk, "up") == 0
&& strcmp(dkk, "pick") == 0)
ok = TRUE;
if (strcmp(dk, "down") == 0
&& (strcmp(dkk, "put") == 0 || verbs[vrbx] == THROW) )
ok = TRUE;
} else {
/* object follows preposition See if it's plausible. */
kk = abs(ptab[vrbkey]) % 1000;
if (kk == word && kk == ALL) {
if (!do_scoop_up())
return (FALSE);
} else if (!(kk == word || kk == 999)) {
vrbkey++;
ok = ptab[vrbkey - 1] < 0 ? FALSE : TRUE;
}
}
}
return (ok);
}
static boolean do_scoop_up()
{
int i, val;
val = VAL(verbs[vrbx]);
if (val == DROP || val == PUT || val == LEAVE) {
for (i = 1; i < MAXOBJ; i++) {
if (!athand(i) || g.fixed[i])
continue;
if (i > WATER && i <= WINE + 1)
continue;
if (toting(i)) {
objs[++objx] = i;
otxt[objx] = "BUG???";
if (objx >= 44)
break;
}
}
}
if (val == TAKE || val == PICK || val == GET) {
if (blind()) {
rspeak(357);
return (FALSE);
} else {
for (i = 1; i < MAXOBJ; i++) {
if (!athand(i) || g.fixed[i])
continue;
if (i > WATER && i <= WINE + 1)
continue;
if (!toting(i)) {
objs[++objx] = i;
otxt[objx] = "BUG???";
if (objx >= 44)
break;
}
}
}
}
return (TRUE);
}
static boolean check_next()
{
word = words[wdx + 1];
if (word > 0)
return (TRUE);
else if (word == 0)
rspeak(confuz());
else {
if (pct(50))
printf("I don't understand the word %s?\n", txt[wdx]);
else
printf("Mumble ? %s\n", txt[wdx]);
words[wdx+1] = 0;
}
return (FALSE);
}

264
commands/advent/initial.c Executable file
View file

@ -0,0 +1,264 @@
/*
Initialization of adventure play variables
*/
#include <string.h>
#include <stdio.h>
#include "advent.h" /* #define preprocessor equates */
#define EXTERN /* define, not declare, in advdec.h */
#include "advdec.h"
int plac[MAXOBJ] = {
0, 0, 3, 8, 10, 11, 0, 14, 0, 148, /* 0 - 9 */
96, 19, 17, 101, 103, 0, 106, 0, 0, 238, /* 10 - 19 */
238, 117, 190, 109, 25, 23, 111, 35, 0, 97, /* 20 - 29 */
0, 119, 0, 117, 0, 130, 0, 126, 140, 0, /* 30 - 39 */
96, 94, 158, 160, 188, 0, 155, 174, 166, 228, /* 40 - 49 */
18, 204, 27, 29, 30, 0, 92, 168, 97, 100, /* 50 - 59 */
101, 0, 119, 127, 130, 141, 144, 205, 28, 182, /* 60 - 69 */
225, 230, 0, 147, 241, 248, 0, 0, 0, 0, /* 70 - 79 */
0, 0, 0, 0, 0, 0, 0, 193, 102, 0, /* 80 - 89 */
159, 141, 172, 188, 189, 0, 0, 193, 227, 174, /* 90 - 99 */
0, 13, 238, 217, 171, 0, 146, 159, 3, 0, /* 100 - 109 */
0, 0, 0, 3, 180, 39, 5, 0, 110, 169, /* 110 - 119 */
200
};
int fixd[MAXOBJ] = {
0, 0, 0, 9, 0, 0, 0, 15, 0, 0, /* 0 - 9 */
0, -1, 27, -1, 0, 0, 0, -1, 0, 0, /* 10 - 19 */
0, 122, 235, -1, -1, 67, -1, 110, 0, -1, /* 20 - 29 */
-1, 121, 0, 122, 0, -1, -1, -1, -1, 0, /* 30 - 39 */
-1, -1, 166, 167, 189, 0, 0, -1, 0, 229, /* 40 - 49 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 50 - 59 */
0, 0, 121, 0, -1, 0, 0, 0, 0, 0, /* 60 - 69 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 70 - 79 */
0, 0, 0, 0, 0, 0, 0, -1, 194, -1, /* 80 - 89 */
0, -1, 174, -1, -1, 0, 0, -1, -1, -1, /* 90 - 99 */
0, 0, 0, -1, -1, -1, 0, 0, 0, 0, /* 100 - 109 */
0, 0, -1, 0, 0, -1, -1, 0, 0, 0, /* 110 - 119 */
0
};
struct playinfo g = {
0, /* turns */
1, /* loc */
1, /* oldloc */
1, /* oldloc2 */
1, /* newloc */
{ /* loc_attrib[MAXLOC] */
0, 73, 65, 73, 73, /* 0 - 4 */
65, 65, 73, 1601, 33, /* 5 - 9 */
32, 32, 32, 1824, 32, /* 10 - 14 */
0, 2, 0, 0, 2816, /* 15 - 19 */
2, 2, 2, 0, 10, /* 20 - 24 */
0, 2, 0, 0, 0, /* 25 - 29 */
0, 2, 2, 8, 0, /* 30 - 34 */
0, 0, 0, 8, 0, /* 35 - 39 */
2, 0, 256, 256, 256, /* 40 - 44 */
256, 272, 272, 272, 256, /* 45 - 49 */
256, 0, 256, 256, 272, /* 50 - 54 */
256, 272, 0, 16, 2, /* 55 - 59 */
0, 0, 0, 0, 0, /* 60 - 64 */
0, 0, 0, 0, 0, /* 65 - 69 */
0, 0, 0, 0, 0, /* 70 - 74 */
0, 0, 0, 0, 2, /* 75 - 79 */
256, 256, 272, 0, 0, /* 80 - 84 */
16, 272, 0, 0, 2, /* 85 - 89 */
2, 0, 0, 0, 0, /* 90 - 94 */
8, 0, 0, 1280, 513, /* 95 - 99 */
513, 512, 0, 0, 0, /* 00 - 04 */
0, 0, 0, 768, 0, /* 105 - 109 */
0, 0, 0, 8, 0, /* 110 - 114 */
1, 1, 0, 0, 0, /* 115 - 119 */
0, 0, 16, 16, 16, /* 120 - 124 */
16, 17, 16, 16, 16, /* 125 - 129 */
16, 0, 0, 0, 0, /* 130 - 134 */
0, 0, 0, 0, 0, /* 135 - 139 */
0, 1040, 16, 0, 0, /* 140 - 144 */
2, 65, 65, 65, 65, /* 145 - 149 */
65, 65, 65, 65, 65, /* 150 - 154 */
65, 3, 2625, 2113, 65, /* 155 - 159 */
65, 3, 3, 3, 3, /* 160 - 164 */
3, 41, 41, 9, 9, /* 165 - 169 */
0, 0, 0, 0, 0, /* 170 - 174 */
0, 0, 0, 2, 0, /* 175 - 179 */
0, 2, 0, 0, 0, /* 180 - 184 */
0, 0, 0, 0, 16, /* 185 - 189 */
0, 0, 9, 0, 0, /* 190 - 194 */
0, 0, 0, 9, 2, /* 195 - 199 */
1, 1, 2304, 0, 0, /* 200 - 204 */
0, 8, 8, 8, 0, /* 205 - 209 */
0, 0, 1, 0, 9, /* 210 - 214 */
0, 0, 12, 0, 0, /* 215 - 219 */
0, 0, 0, 0, 0, /* 220 - 224 */
0, 2, 2625, 73, 73, /* 225 - 229 */
0, 2, 2, 2, 2, /* 230 - 234 */
0, 0, 2, 65, 3137, /* 235 - 239 */
65, 65, 65, 65, 65, /* 240 - 244 */
65, 65, 65, 65 /* 245 - 249 */
}, /* loc_attrib[MAXLOC] */
{0 }, /* place[MAXOBJ] */
{0 }, /* fixed[MAXOBJ] */
{ /* weight[MAXOBJ] */
0, 0, 1, 0, 1, 2, 2, 0, 0, 2, /* 0 - 9 */
1, 0, 0, 0, 7, 7, 1, 0, 0, 2, /* 10 - 19 */
1, 0, 0, 0, 0, 0, 0, 0, 3, 0, /* 20 - 29 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 3, /* 30 - 39 */
0, 0, 0, 0, 0, 0, 1, 1, 0, 0, /* 40 - 49 */
6, 1, 2, 2, 3, 5, 4, 3, 2, 3, /* 50 - 59 */
4, 1, 3, 1, 3, 2, 1, 1, 2, 2, /* 60 - 69 */
2, 3, 1, 1, 3, 1, 0, 0, 0, 0, /* 70 - 79 */
0, 2, 2, 2, 2, 2, 2, 0, 0, 0, /* 70 - 79 */
1, 0, 0, 0, 0, 3, 2, 0, 0, 0, /* 80 - 89 */
0, 2, 1, 0, 0, 0, 1, 1, 2, 0, /* 100 - 109 */
3, 3, 0, 1, 1, 0, 0, 0, 3, 1, /* 110 - 119 */
2, 0, 0 /* 120 - 129 */
}, /* weight[MAXOBJ] */
{0 }, /* atloc[MAXLOC] */
{0 }, /* link[MAXOBJ * 2] */
{0 }, /* holder[MAXOBJ] */
{0 }, /* hlink[MAXOBJ] */
{0 }, /* visited[MAXLOC] */
{0 }, /* prop[MAXOBJ] */
{ /* obj_state[MAXOBJ] */
0, 0, 32800, 26, 32770, /* 0 - 4 */
32, 32, 8192, 0, 0, /* 5 - 9 */
32, 512, 0, 256, 770, /* 10 - 14 */
770, 288, 512, 0, 160, /* 15 - 19 */
32802, 0, 0, 0, 128, /* 20 - 24 */
0, 0, 0, 32, 8192, /* 25 - 29 */
512, 512, 0, 512, 0, /* 30 - 34 */
512, 256, 0, 32768, 8224, /* 35 - 39 */
0, 18, 26, 26, 2, /* 40 - 44 */
0, 8320, 18464, 32768, 0, /* 45 - 49 */
16384, 16416, 16416, 26656, 24608, /* 50 - 54 */
49240, 24608, 16384, 49184, 16416, /* 55 - 59 */
16416, 16416, 16384, 16544, 16442, /* 60 - 64 */
16416, 18464, 26656, 16416, 16416, /* 65 - 69 */
49184, 49154, 18464, 18464, 16416, /* 70 - 74 */
16416, 0, 0, 0, 0, /* 75 - 79 */
0, 0, 0, 0, 0, /* 80 - 84 */
0, 0, 8704, 0, 0, /* 85 - 89 */
0, 0, 0, 0, 32768, /* 90 - 94 */
0, 128, 0, 0, 0, /* 95 - 99 */
0, 160, 8224, 0, 0, /* 100 - 104 */
0, 8352, 8352, 32870, 0, /* 105 - 109 */
16674, 258, 32858, 288, 32, /* 110 - 114 */
256, 0, 0, 32866, 16416, /* 115 - 119 */
16416, 0, 0 /* 120 - 123 */
}, /* obj_state[MAXOBJ] */
{ /* points[MAXOBJ] */
0, 0, 0, 0, 0, /* 0 - 4 */
0, 0, 0, 0, 0, /* 5 - 9 */
0, 0, 0, 0, 0, /* 10 - 14 */
0, 1000108, 0, 0, 0, /* 15 - 19 */
0, 0, 0, 0, 0, /* 20 - 24 */
0, 0, 0, 0, 0, /* 25 - 29 */
0, 0, 0, 0, 0, /* 30 - 34 */
0, 0, 0, 0, 0, /* 35 - 39 */
0, 0, 0, 0, 0, /* 40 - 44 */
0, 0, -3000112, 0, 0, /* 45 - 49 */
-2000055, -2000112, -2000112, -1000112, -5000112, /* 50 - 54 */
5000003, -3000112, -2000055, 2000003, -3000112, /* 55 - 59 */
-4000112, -4000112, 3000003, -1000112, -4000112, /* 60 - 64 */
-4000112, -2000112, -3000112, -1000112, -1000112, /* 65 - 69 */
-2000112, -3012055, -4000112, -1000112, -5000112, /* 70 - 74 */
-5000112, 0, 0, 0, 0, /* 75 - 79 */
0, 0, 0, 0, 0, /* 80 - 84 */
0, 0, 0, 0, 0, /* 85 - 89 */
0, 0, 0, 0, 0, /* 90 - 94 */
0, 0, 0, 0, 0, /* 95 - 99 */
0, 0, 0, 0, 0, /* 100 - 104 */
0, 0, 0, 0, 0, /* 105 - 109 */
-2000112, 0, 0, 0, 0, /* 110 - 114 */
0, 0, 0, 0, -4000118, /* 115 - 119 */
-2000112, 0 /* 120 - 122 */
}, /* points[MAXOBJ] */
{0 }, /* hinted[HNTMAX+1] */
{ /* hints[HNTMAX+1][5] */
{ 0, 0, 0, 0, 0 }, /* 0 */
{ 0, 9999, 4, 0, 0 }, /* 1 */
{ 0, 9999, 10, 0, 0 }, /* 2 */
{ 0, 9999, 5, 0, 0 }, /* 3 */
{ 0, 0, 0, 0, 0 }, /* 4 */
{ 0, 0, 0, 0, 0 }, /* 5 */
{ 0, 0, 0, 0, 0 }, /* 6 */
{ 0, 15, 4, 176, 177 }, /* 7 */
{ 0, 8, 5, 178, 179 }, /* 8 */
{ 0, 13, 3, 180, 181 }, /* 9 */
{ 0, 6, 10, 211, 212 }, /* 10 */
{ 0, 6, 5, 213, 214 }, /* 11 */
{ 0, 4, 2, 62, 63 }, /* 12 */
{ 0, 5, 2, 18, 19 }, /* 13 */
{ 0, 4, 2, 62, 233 }, /* 14 */
{ 0, 6, 5, 274, 275 }, /* 15 */
{ 0, 10, 5, 289, 290 }, /* 16 */
{ 0, 8, 2, 20, 21 }, /* 17 */
{ 0, 5, 2, 404, 405 } /* 18 */
}, /* hints[HNTMAX+1][5] */
{0 }, /* hintlc[HNTMAX+1] */
0, /* tally */
0, /* tally2 */
0, /* limit */
0, /* lmwarn */
0, /* wzdark */
0, /* closing */
0, /* closed */
0, /* holding */
0, /* detail */
0, /* knfloc */
30, /* clock */
50, /* clock2 */
0, /* panic */
{ 0, 19, 27, 33, 44, 64, 114 }, /* dloc[DWARFMAX+1] */
0, /* dflag */
{ 0, 0, 0, 0, 0, 0, 0 }, /* dseen[DWARFMAX+1] */
{ 0, 0, 0, 0, 0, 0, 0 }, /* odloc[DWARFMAX+1] */
18, /* daltloc */
0, /* dkill */
114, /* chloc */
140, /* chloc2 */
0, /* bonus */
0, /* numdie */
0, /* foobar */
0, /* combo */
0, /* terse */
5, /* abbnum */
100, /* health */
0, /* chase */
FALSE, /* flg239 */
0 /* lastglob */
};
/*
Initialization of adventure play variables
*/
void initialize()
{
int i;
for (i = MAXOBJ; i > 0; i--) {
g.fixed[i] = fixd[i];
if (fixd[i] > 0) {
drop(i + MAXOBJ, fixd[i]);
drop(i, plac[i]);
}
if ((plac[i] != 0) && (fixd[i] <= 0))
drop(i, plac[i]);
}
for (i = 1; i <= MAXOBJ; i++) {
if (treasr(i)) {
g.prop[i] = -1;
g.tally++;
}
}
newtravel = TRUE;
g.place[BOOK] = -1;
insert(BOOK, SAFE);
g.place[WATER] = -1;
insert(WATER, BOTTLE);
g.prop[BOTTLE] = 8;
return;
}

597
commands/advent/itverb.c Executable file
View file

@ -0,0 +1,597 @@
/* program ITVERB.C */
#include <stdio.h>
#include "advent.h"
#include "advdec.h"
_PROTOTYPE(void needobj, (void));
_PROTOTYPE(void ivtake, (void));
_PROTOTYPE(void ivopen, (void));
_PROTOTYPE(void ivkill, (void));
_PROTOTYPE(void ivdrink, (void));
_PROTOTYPE(void ivquit, (void));
_PROTOTYPE(void ivfoo, (void));
_PROTOTYPE(void inventory, (void));
_PROTOTYPE(void addobj, (int obj));
_PROTOTYPE(void ivpour, (void));
_PROTOTYPE(void ivfill, (void));
_PROTOTYPE(void ivbrief, (void));
_PROTOTYPE(void ivread, (void));
_PROTOTYPE(void ivcombo, (void));
_PROTOTYPE(void iveat, (void));
/*
Routines to process intransitive verbs
*/
void itverb()
{
int i;
newtravel = FALSE;
switch (verb) {
case DROP:
case SAY:
case WAVE:
case CALM:
case RUB:
case THROW:
case FIND:
case FEED:
case BREAK:
case WAKE:
case WEAR:
case HIT:
case DIAL:
case PLAY:
case PICK:
case PUT:
case TURN: needobj(); break;
case TAKE:
case YANK:
case GET:
case INSRT:
case REMOVE:
case BURN: ivtake(); break;
case OPEN:
case CLOSE:
case LOCK:
case UNLOCK: ivopen(); break;
case NOTHING: rspeak(54); break;
case ON:
case OFF: trverb(); break;
case WALK: actspk(verb); break;
case KILL: ivkill(); break;
case POUR: ivpour(); break;
case EAT: iveat(); break;
case DRINK: ivdrink(); break;
case QUIT: ivquit(); break;
case INVENTORY: inventory(); break;
case FILL: ivfill(); break;
case BLAST: ivblast(); break;
case SCORE: score(TRUE); break;
case FOO: ivfoo(); break;
case BRIEF: ivbrief(); break;
case READ: ivread(); break;
case SUSPEND:
if (g.closing)
rspeak(378);
else
saveadv("advent.sav");
break;
case RESTORE: restore("advent.sav"); break;
case ANSWER:
if ((g.loc != 189) || (g.prop[PHONE] != 0))
needobj();
else {
object = PHONE;
itverb();
}
break;
case BLOW: rspeak(268); break;
/* Action verb 'LEAVE' has no object */
case LEAVE: bug(29); break;
/* Call if no phone is handy, yell. */
case YELL:
if (!here(PHONE))
needobj();
else if (!g.closed)
rspeak(271);
else {
rspeak(283);
normend();
}
break;
/* Health. give him a diagnosis. */
case HEALTH:
if (g.numdie)
fprintf(stdout, "You have been killed %d times otherwise\n",
g.numdie);
if (g.health >= 95) {
if (pct(50))
rspeak(348);
else
rspeak(349);
} else {
fprintf(stdout,
"Your health rating is %2d out of a possible 100.\n",
g.health);
rspeak(381 + (100 - g.health) / 20);
}
break;
case LOOK: ivlook(); break;
case COMBO:
if (at(SAFE))
ivcombo();
break;
case SWEEP:
/* Dust/sweep */
if (!at(CARVNG) || !athand(BRUSH) || (g.prop[CARVNG] == 1))
rspeak(342);
else {
g.prop[CARVNG] = 1;
rspeak(363);
rspeak(372);
}
break;
case TERSE:
/* Terse/unterse. supress all long_form descriptions. */
g.terse = !g.terse;
g.detail = 3;
rspeak(54);
break;
case WIZ:
is_wiz = !is_wiz;
case MAP:
rspeak(54);
break;
case GATE:
if (is_wiz) {
static char buf[INPUTBUFLEN];
sscanf(ask("Location ? ", buf, sizeof(buf)), "%d", &g.loc);
}
rspeak(54);
break;
case PIRLOC:
if (is_wiz) {
fprintf(stdout, "The dwarfs are at locations:\n");
for (i = 1; i < DWARFMAX; i++)
fprintf(stdout, " %4d", g.dloc[i]);
fprintf(stdout, "\nThe pirate is at location %4d\n",
g.dloc[DWARFMAX]);
}
rspeak(54);
break;
default:
printf("This intransitive not implemented yet\n");
}
return;
}
/*
Routine to indicate no reasonable
object for verb found. Used mostly by
intransitive verbs.
*/
void needobj()
{
printf("%s what?\n", vtxt[vrbx]);
return;
}
/*
CARRY, TAKE etc.
*/
void ivtake()
{
int anobj, item;
anobj = 0;
for (item = 1; item < MAXOBJ; ++item)
if (g.place[item] == g.loc)
if (anobj == 0)
anobj = item;
else {
needobj();
return;
}
if (anobj == 0 || (dcheck() && g.dflag >= 2) || blind())
needobj();
else {
object = anobj;
if (verb == YANK)
vyank();
else if (verb == WEAR)
vwear();
else
vtake();
}
return;
}
/*
OPEN, LOCK, UNLOCK
*/
void ivopen()
{
int obj_cnt, item;
for (item = 1, obj_cnt = 0; item < MAXOBJ; item++) {
if ((g.place[item] == g.loc) && (hinged(item))) {
object = item;
obj_cnt++;
}
}
if (obj_cnt != 1)
needobj();
else if (verb == LOCK)
vlock();
else if (verb == UNLOCK)
vunlock();
else if (verb == SHUT)
vclose();
else
vopen();
}
/*
ATTACK, KILL etc
*/
boolean previous_obj;
void ivkill()
{
previous_obj = FALSE;
if (dcheck() && g.dflag >= 2)
object = DWARF;
if (here(SNAKE))
addobj(SNAKE);
if (at(DRAGON) && g.prop[DRAGON] == 0)
addobj(DRAGON);
if (at(TROLL))
addobj(TROLL);
if (here(GNOME))
addobj(GNOME);
if (here(BEAR) && g.prop[BEAR] == 0)
addobj(BEAR);
if (here(WUMPUS) && g.prop[WUMPUS] == 0)
addobj(WUMPUS);
/* Can't attack bird by throwing axe */
if (here(BIRD) && verb != THROW)
addobj(BIRD);
/* Clam and oyster both treated as clam for intransitive case; no
harm done. */
if (here(CLAM) || here(OYSTER))
addobj(CLAM);
if ((previous_obj) || (object == 0))
rspeak(44);
else
vkill();
return;
}
/*
POUR if no object, assume liq in container, if holding one.
*/
void ivpour()
{
if ((holding(BOTTLE)) && (liq(BOTTLE) != 0) && !holding(CASK))
object = BOTTLE;
if ((holding(CASK)) && (liq(CASK) != 0) && !holding(BOTTLE))
object = CASK;
if (object == 0)
needobj();
else
trverb();
}
/*
EAT. intransitive: assume edible if present, else ask what.
If he as more than one edible, or none, 'EAT' is ambiguous
without an explicit object.
*/
void iveat()
{
int i;
previous_obj = FALSE;
for (i = 1; i < MAXOBJ; i++) {
if ((here(i)) && (edible(i)))
addobj(i);
}
if ((previous_obj) || (object == 0))
needobj();
else
trverb();
}
/*
DRINK. If no object, assume water or wine and look for them here.
If potable is in bottle or cask, drink that. If not, see if there
is something drinkable nearby (stream, lake, wine fountain, etc.),
and drink that. If he has stuff in both containers, ask which.
*/
void ivdrink()
{
int ll;
previous_obj = FALSE;
ll = liqloc(g.loc);
if ((ll == WATER) || (ll == WINE)) {
object = ll;
iobj = -1;
}
ll = liq(BOTTLE);
if ((athand(BOTTLE)) && ((ll == WATER) || (ll == WINE))) {
object = ll;
iobj = BOTTLE;
}
ll = liq(CASK);
if ((athand(CASK)) && ((ll == WATER) || (ll == WINE))
&& iobj != BOTTLE) {
object = ll;
iobj = CASK;
} else
object = 0;
if (object == 0)
needobj();
else
trverb();
}
/*
QUIT intransitive only. Verify intent and exit if that's what he wants
*/
void ivquit()
{
gaveup = yes(22, 54, 54);
if (gaveup)
normend();
return;
}
/*
INVENTORY
*/
void inventory()
{
int i, msg;
boolean init_msg;
init_msg = TRUE;
msg = 98;
for (i = 1; i < MAXOBJ; i++) {
if (!holding(i) || wearng(i) || i == BEAR || i == BOAT)
continue;
if (init_msg)
rspeak(99);
pspeak(i, -1);
init_msg = FALSE;
msg = 0;
lookin(i);
}
/* Tell him what he is wearing */
init_msg = TRUE;
for (i = 1; i < MAXOBJ; i++) {
if (wearng(i)) {
if (init_msg)
fprintf(stdout, "\nYou are wearing:\n");
fprintf(stdout, " ");
pspeak(i, -1);
msg = 0;
init_msg = FALSE;
}
}
if (holding(BOAT)) {
rspeak(221);
lookin(BOAT);
}
if (holding(BEAR))
msg = 141;
if (msg)
rspeak(msg);
return;
}
/*
FILL bottle or cask must be empty, and some liquid avaible
*/
void ivfill()
{
if ((g.prop[CASK] == 1) && !here(CASK))
object = CASK;
if ((g.prop[BOTTLE] == 1) && !here(BOTTLE))
object = BOTTLE;
if ((here(BOTTLE) && here(CASK)) || (object == 0))
needobj();
else
trverb();
}
/*
BLAST etc.
*/
void ivblast()
{
if (!g.closed)
actspk(verb);
else {
g.bonus = 135;
if (g.place[ROD2] == 212 && g.loc == 116)
g.bonus = 133;
if (g.place[ROD2] == 116 && g.loc != 116)
g.bonus = 134;
rspeak(g.bonus);
normend();
}
return;
}
/*
Handle fee fie foe foo...
*/
void ivfoo()
{
int k;
int msg;
k = VAL(vocab(vtxt[vrbx], MISC));
if (g.foobar != 1 - k) {
if (g.foobar == 0)
msg = 42;
else
msg = 151;
rspeak(msg);
return;
}
g.foobar = k;
if (k != 4)
return;
g.foobar = 0;
if (g.place[EGGS] == plac[EGGS] ||
(toting(EGGS) && g.loc == plac[EGGS])) {
rspeak(42);
return;
}
/* Bring back troll if we steal the eggs back from him before
crossing */
if (g.place[EGGS] == 0 && g.place[TROLL] == 0 && g.prop[TROLL] == 0)
g.prop[TROLL] = 1;
if (here(EGGS))
k = 1;
else if (g.loc == plac[EGGS])
k = 0;
else
k = 2;
move(EGGS, plac[EGGS]);
pspeak(EGGS, k);
return;
}
/*
brief/unbrief. intransitive only.
suppress long descriptions after first time.
*/
void ivbrief()
{
int msg;
g.detail = 3;
g.terse = FALSE;
if (g.abbnum != 10000) {
msg = 156;
g.abbnum = 10000;
} else {
msg = 374;
g.abbnum = 5;
}
rspeak(msg);
}
/*
read etc...
*/
void ivread()
{
previous_obj = FALSE;
if (here(BOOK))
object = BOOK;
if (here(BOOK2))
addobj(BOOK2);
if (here(BILLBD))
addobj(BILLBD);
if (here(CARVNG))
addobj(CARVNG);
if (here(MAGAZINE))
addobj(MAGAZINE);
if (here(MESSAGE))
addobj(MESSAGE);
if (here(OYSTER))
addobj(OYSTER);
if (here(POSTER))
addobj(POSTER);
if (here(TABLET))
addobj(TABLET);
if (previous_obj || object == 0 || dark())
needobj();
else
vread();
return;
}
/*
LOOK. can't give more detail. Pretend it wasn't dark (though it may "now"
be dark) so he won't fall into a pit staring into the gloom.
*/
void ivlook()
{
if (g.detail++ < 3)
rspeak(15);
g.wzdark = FALSE;
g.visited[g.loc] = 0;
g.newloc = g.loc;
newtravel = TRUE;
return;
}
/*
COMBO: trying to open safe. (see comments for fee fie foe foo)
*/
void ivcombo()
{
int k, msg;
k = VAL(vocab(vtxt[vrbx], MISC)) - 10;
msg = 42;
if (g.combo != 1 - k) {
if (g.combo != 0)
msg = 366;
rspeak(msg);
return;
}
g.combo = k;
if (k != 3)
rspeak(371);
else {
g.combo = 0;
bitoff(SAFE, LOCKBT);
biton(SAFE, OPENBT);
g.prop[SAFE] = 1;
if (g.prop[BOOK] < 0) {
g.tally--;
g.prop[BOOK] = 0;
/* If remaining treasures too elusive, zap his lamp. this
duplicates some code, must be done here since book is
contained ins safe & tally stuff only works for thing
deposited at a location. */
if ((g.tally == g.tally2) && (g.tally != 0))
g.limit = (g.limit < 35) ? g.limit : 35;
}
rspeak(365);
}
}
/*
ensure uniqueness as objects are searched
out for an intransitive verb
*/
void addobj(obj)
int obj;
{
if (!previous_obj) {
if (object != 0)
previous_obj = TRUE;
else
object = obj;
}
return;
}

199
commands/advent/score.c Executable file
View file

@ -0,0 +1,199 @@
/**
SCORE
Calculate what the player's score would be if he quit now.
This may be the end of the game, or he may just be wondering
how he is doing.
The present scoring algorithm is as follows:
(treasure points are explained in a following comment)
objective: points: present total possible:
getting well into cave 25 25
total possible for treasures (+mag) 426
reaching "closing" 20 20
"closed": quit/killed 10
klutzed 20
wrong way 25
success 30 30
total: 501
(points can also be deducted for using hints or deaths.)
*/
#include <stdio.h>
#include "advent.h"
#include "advdec.h"
void score(scorng)
boolean scorng;
{
int cur_score, max_score, qk[3];
int obj, num_treas, k, i;
long t;
char *kk2c;
cur_score = 0;
max_score = 0;
num_treas = 0;
/** First tally up the treasures. Must be in building and not broken.
give the poor guy partial score just for finding each treasure.
Gets full score, qk[3], for obj if:
obj is at loc qk[1], and
obj has prop value of qk[2]
weight total possible
magazine 1 (absolute) 1
all the following are multiplied by 5 (range 5-25):
book 2
cask 3 (with wine only)
chain 4 (must enter via styx)
chest 5
cloak 3
clover 1
coins 5
crown 2
crystal-ball 2
diamonds 2
eggs 3
emerald 3
grail 2
horn 2
jewels 1
lyre 1
nugget 2
pearl 4
pyramid 4
radium 4
ring 4
rug 3
sapphire 1
shoes 3
spices 1
sword 4
trident 2
vase 2
droplet 5
tree 5
total: 85 * 5 = 425 + 1 ==> 426
*/
for (obj = 1; obj < MAXOBJ; obj++) {
if (g.points[obj] == 0)
continue;
t = g.points[obj];
qk[0] = (int) (t < 0L ? -((t = -t) % 1000) : (t % 1000));
t /= 1000;
qk[1] = (int) (t % 1000);
qk[2] = (int) (t / 1000);
k = 0;
if (treasr(obj)) {
num_treas++;
k = qk[2] * 2;
if (g.prop[obj] >= 0)
cur_score += k;
qk[2] *= 5;
}
if ((g.place[obj] == qk[0]) && (g.prop[obj] == qk[1])
&& ((g.place[obj] != -CHEST) || (g.place[CHEST] == 3))
&& ((g.place[obj] != -SHIELD) || (g.place[SHIELD] == -SAFE))
)
cur_score += qk[2] - k;
max_score += qk[2];
}
/**
Now look at how he finished and how far he got. Maxdie and numdie tell us
how well he survived. Gaveup says whether he exited via quit. Dflag will
tell us if he ever got suitably deep into the cave. Closing still indicates
whether he reached the endgame. And if he got as far as "cave closed"
(indicated by "closed"), then bonus is zero for mundane exits or 133, 134,
135 if he blew it (so to speak).
*/
if (g.dflag)
cur_score += 25;
max_score += 25;
if (g.closing)
cur_score += 20;
max_score += 20;
if (g.closed) {
if (g.bonus == 0)
cur_score += 10;
else if (g.bonus == 135)
cur_score += 20;
else if (g.bonus == 134)
cur_score += 25;
else if (g.bonus == 133)
cur_score += 30;
}
max_score += 30;
/* Deduct points for hints, deaths and quiting.
hints < hntmin are special; see database description
*/
for (i = 1; i <= HNTMAX; i++)
if (g.hinted[i])
cur_score -= g.hints[i][2];
cur_score -= g.numdie * 10;
if (gaveup)
cur_score -= 4;
fprintf(stdout, "You have found %3d out of %3d Treasures,",
num_treas - g.tally, num_treas);
fprintf(stdout, " using %4d turns\n", g.turns);
fprintf(stdout, "For a score of: %4d", cur_score);
fprintf(stdout, " out of a possible %4d\n", max_score);
if (cur_score < 110) {
fprintf(stdout, "You are obviously a rank amateur.");
if (!scorng)
fprintf(stdout, " Better luck next time.");
fputc('\n', stdout);
k = 110 - cur_score;
} else if (cur_score < 152) {
fprintf(stdout,
"Your score qualifies you as a Novice Class Adventurer.\n");
k = 152 - cur_score;
} else if (cur_score < 200) {
fprintf(stdout,
"You have achieved the rating: \"Experienced Adventurer\".\n");
k = 200 - cur_score;
} else if (cur_score < 277) {
fprintf(stdout,
"You may now consider yourself a \"Seasoned Adventurer\".\n");
k = 277 - cur_score;
} else if (cur_score < 345) {
fprintf(stdout,
"You have reached \"Junior Master\" status.\n");
k = 345 - cur_score;
} else if (cur_score < 451) {
fprintf(stdout,
"Your score puts you in Master Adventurer Class C.\n");
k = 451 - cur_score;
} else if (cur_score < 471) {
fprintf(stdout,
"Your score puts you in Master Adventurer Class B.\n");
k = 471 - cur_score;
} else if (cur_score < 501) {
fprintf(stdout,
"Your score puts you in Master Adventurer Class A.\n");
k = 501 - cur_score;
} else {
fprintf(stdout,
"All of Adventuredom gives tribute to you, Adventurer Grandmaster!\n");
k = 0;
}
if (!scorng) {
kk2c = (k == 1) ? "." : "s.";
printf("\nTo acheive the next higher rating,");
if (cur_score == 501)
printf(" would be a neat trick!\n\n CONGRATULATIONS!!\n");
else
printf(" you need %3d more point%s\n", k, kk2c);
}
return;
}

99
commands/advent/setup.c Executable file
View file

@ -0,0 +1,99 @@
/** program SETUP.C *
* execution will read the four adventure text files *
* files; "advent1.txt", "advent2.txt", "advent3.txt" & *
* "advent4.txt". it will create the file "advtext.h" *
* which is an Index Sequential Access Method (ISAM) *
* header to be #included into "advent.c" before the *
* header "advdec.h" is #included. */
#include <stdio.h>
#include <stdlib.h>
#include "advent.h"
_PROTOTYPE(int main, (void));
_PROTOTYPE(void file_error, (char *));
_PROTOTYPE(void encode, (unsigned char *));
int main()
{
FILE *isam, *src, *dest;
char itxt[255];
int cnt, i;
long llen;
char filename[12];
static char *headername[] = {
"idx1[MAXLOC]", "idx2[MAXLOC]", "idx3[MAXOBJ]", "idx4[MAXMSG]",
};
long x29 = (1L << 29), x30 = (1L << 30);
if (!(x30 / 2 == x29 && 0L < x30 && x29 < x30)) {
fprintf(stderr, "Sorry, advent needs 32-bit `long int's.\n");
exit(EXIT_FAILURE);
}
isam = fopen("advtext.h", "w");
if (!isam) {
fprintf(stderr, "Sorry, I can't open advtext.h...\n");
exit(EXIT_FAILURE);
}
fprintf(isam, "\n/*\theader: ADVTEXT.H\t\t\t\t\t*/\n\n\n");
for (i = 1; i <= 4; i++) {
cnt = -1;
llen = 0L;
sprintf(filename, "advent%d.txt", i);
src = fopen(filename, "r");
if (!src)
file_error(filename);
sprintf(filename, "advent%d.dat", i);
dest = fopen(filename, "w");
if (!dest)
file_error(filename);
fprintf(isam, "long\t%s = {\n\t", headername[i - 1]);
while (fgets(itxt, 255, src)) {
encode((unsigned char *) itxt);
if (fprintf(dest, "%s\n", itxt) == EOF)
file_error(filename);
if (itxt[0] == '#') {
if (llen)
fprintf(isam, "%ld,%s\t", llen,
&"\0\0\0\0\0\0\0\n"[++cnt & 7]);
llen = ftell(dest);
if (llen <= 0) {
fprintf(stderr, "ftell err in %s\n", filename);
exit(EXIT_FAILURE);
} /* if (!llen) */
} /* if (itxt[0]) */
} /* while fgets */
if (fprintf(isam, "%ld\n\t};\n\n", llen) == EOF)
file_error("advtext.h");
fclose(src);
if (fclose(dest) == EOF)
file_error(filename);
}
if (fclose(isam) == EOF)
file_error("advtext.h");
return EXIT_SUCCESS;
} /* main */
void file_error(filename)
char *filename;
{
perror(filename);
exit(EXIT_FAILURE);
}
_CONST unsigned char key[4] = {'c' | 0x80, 'L' | 0x80, 'y' | 0x80, 'D' | 0x80};
void encode(msg)
unsigned char *msg;
{
register int i;
for (i = 1; msg[i]; i++)
msg[i] ^= key[i & 3];
msg[--i] = '\0';
return;
}

336
commands/advent/travel.c Executable file
View file

@ -0,0 +1,336 @@
/* module TRAVEL.C *
* Routine to handle motion requests */
#include <stdio.h>
#include <stdlib.h>
#include "advent.h"
#include "advdec.h"
#include "advcave.h"
struct trav travel[MAXTRAV];
static int kalflg;
static int bcrossing = 0;
static int phuce[2][4] = {158, 160, 167, 166,
160, 158, 166, 167};
_PROTOTYPE(static void goback, (void));
_PROTOTYPE(static void ck_kal, (void));
_PROTOTYPE(static void dotrav, (void));
_PROTOTYPE(static void badmove, (void));
_PROTOTYPE(static void spcmove, (int rdest));
void domove()
{
gettrav(g.loc, travel);
switch (motion) {
case NULLX:
break;
case BACK:
goback();
break;
case CAVE:
if (outside(g.loc))
rspeak(57);
else
rspeak(58);
break;
default:
g.oldloc2 = g.oldloc;
g.oldloc = g.loc;
dotrav();
}
newtravel = TRUE;
return;
}
/*
Routine to handle request to return
from whence we came!
*/
static void goback()
{
int kk, k2, want, temp;
struct trav strav[MAXTRAV];
want = forced(g.oldloc) ? g.oldloc2 : g.oldloc;
g.oldloc2 = g.oldloc;
g.oldloc = g.loc;
k2 = 0;
if (want == g.loc) {
rspeak(91);
ck_kal();
return;
}
for (kk = 0; travel[kk].tdest != -1; ++kk) {
if (!travel[kk].tcond && travel[kk].tdest == want) {
motion = travel[kk].tverb;
dotrav();
return;
}
if (!travel[kk].tcond) {
temp = travel[kk].tdest;
gettrav(temp, strav);
if (forced(temp) && strav[0].tdest == want)
k2 = temp;
}
}
if (k2) {
motion = travel[k2].tverb;
dotrav();
} else
rspeak(140);
ck_kal();
return;
}
static void ck_kal()
{
if (g.newloc >= 242 && g.newloc <= 247) {
if (g.newloc == 242)
kalflg = 0;
else if (g.newloc == (g.oldloc + 1))
kalflg++;
else
kalflg = -10;
}
}
/*
Routine to figure out a new location
given current location and a motion.
*/
static void dotrav()
{
unsigned char mvflag, hitflag, kk;
int rdest, rverb, rcond, robject;
int pctt;
g.newloc = g.loc;
mvflag = hitflag = 0;
pctt = ranz(100);
for (kk = 0; travel[kk].tdest >= 0 && !mvflag; ++kk) {
rdest = travel[kk].tdest;
rverb = travel[kk].tverb;
rcond = travel[kk].tcond;
robject = rcond % 100;
if ((rverb != 1) && (rverb != motion) && !hitflag)
continue;
++hitflag;
switch (rcond / 100) {
case 0:
if ((rcond == 0) || (pctt < rcond))
++mvflag;
break;
case 1:
if (robject == 0)
++mvflag;
else if (toting(robject))
++mvflag;
break;
case 2:
if (toting(robject) || at(robject))
++mvflag;
break;
case 3:
case 4:
case 5:
case 7:
if (g.prop[robject] != (rcond / 100) - 3)
++mvflag;
break;
default:
bug(37);
}
}
if (!mvflag)
badmove();
else if (rdest > 500)
rspeak(rdest - 500);
else if (rdest > 300)
spcmove(rdest);
else {
g.newloc = rdest;
ck_kal();
}
newtravel = TRUE;
return;
}
/*
The player tried a poor move option.
*/
static void badmove()
{
int msg;
msg = 12;
if (motion >= 43 && motion <= 50)
msg = 9;
if (motion == 29 || motion == 30)
msg = 9;
if (motion == 7 || motion == 36 || motion == 37)
msg = 10;
if (motion == 11 || motion == 19)
msg = 11;
if (motion == 62 || motion == 65 || motion == 82)
msg = 42;
if (motion == 17)
msg = 80;
rspeak(msg);
return;
}
/*
Routine to handle very special movement.
*/
static void spcmove(rdest)
int rdest;
{
int load, obj, k;
switch (rdest - 300) {
case 1: /* plover movement via alcove */
load = burden(0);
if (!load || (load == burden(EMERALD) && holding(EMERALD)))
g.newloc = (99 + 100) - g.loc;
else
rspeak(117);
break;
case 2: /* trying to remove plover, bad
route */
if (enclosed(EMERALD))
extract(EMERALD);
drop(EMERALD, g.loc);
g.newloc = 33;
break;
case 3: /* troll bridge */
if (g.prop[TROLL] == 1) {
pspeak(TROLL, 1);
g.prop[TROLL] = 0;
move(TROLL2, 0);
move((TROLL2 + MAXOBJ), 0);
move(TROLL, plac[TROLL]);
move((TROLL + MAXOBJ), fixd[TROLL]);
juggle(CHASM);
g.newloc = g.loc;
} else {
g.newloc = plac[TROLL] + fixd[TROLL] - g.loc;
if (g.prop[TROLL] == 0)
g.prop[TROLL] = 1;
if (toting(BEAR)) {
rspeak(162);
g.prop[CHASM] = 1;
g.prop[TROLL] = 2;
drop(BEAR, g.newloc);
g.fixed[BEAR] = -1;
g.prop[BEAR] = 3;
if (g.prop[SPICES] < 0)
++g.tally2;
g.oldloc2 = g.newloc;
death();
}
}
break;
case 4:
/* Growing or shrinking in area of tiny door. Each time he
does this, everything must be moved to the new loc.
Presumably, all his possesions are shrunk or streched along
with him. Phuce[2][4] is an array containg four pairs of
"here" (K) and "there" (KK) locations. */
k = phuce[0][g.loc - 161];
g.newloc = phuce[1][g.loc - 161];
for (obj = 1; obj < MAXOBJ; obj++) {
if (obj == BOAT)
continue;
if (g.place[obj] == k && (g.fixed[obj] == 0 || g.fixed[obj] == -1))
move(obj, g.newloc);
}
break;
case 5:
/* Phone booth in rotunda. Trying to shove past gnome, to get
into phone booth. */
if ((g.prop[BOOTH] == 0 && pct(35)) || g.visited[g.loc] == 1) {
rspeak(263);
g.prop[BOOTH] = 1;
move(GNOME, 188);
} else {
if (g.prop[BOOTH] == 1)
rspeak(253);
else
g.newloc = 189;
}
break;
case 6:
/* Collapsing clay bridge. He can cross with three (or fewer)
thing. If more, of if carrying obviously heavy things, he
may end up in the drink. */
g.newloc = g.loc == 235 ? 190 : 235;
bcrossing++;
load = burden(0);
if (load > 4) {
k = (load + bcrossing) * 6 - 10;
if (!pct(k))
rspeak(318);
else {
rspeak(319);
g.newloc = 236;
if (holding(LAMP))
move(LAMP, 236);
if (toting(AXE) && enclosed(AXE))
extract(AXE);
if (holding(AXE))
move(AXE, 208);
for (obj = 1; obj < MAXOBJ; obj++)
if (toting(obj))
destroy(obj);
g.prop[CHASM2] = 1;
}
}
break;
case 7:
/* Kaleidoscope code is here. */
if (kalflg == 5) {
g.newloc = 248;
g.oldloc = 247;
} else {
g.newloc = 242 + ranz(5);
g.oldloc = g.newloc - 1;
kalflg = g.newloc == 242 ? 0 : -10;
}
break;
default:
bug(38);
}
return;
}
/*
Routine to fill travel array for a given location
*/
void gettrav(loc, travel)
int loc;
struct trav *travel;
{
int i;
long t, *lptr;
lptr = cave[loc - 1];
for (i = 0; i < MAXTRAV; i++) {
t = *lptr++;
if (!(t)) {
travel->tdest = -1; /* end of array */
return; /* terminate for loop */
}
travel->tverb = (int) (t % 1000);
t /= 1000;
travel->tdest = (int) (t % 1000);
t /= 1000;
travel->tcond = (int) (t % 1000);
travel++;
}
bug(25);
return;
}

729
commands/advent/turn.c Executable file
View file

@ -0,0 +1,729 @@
/* program TURN.C */
#include <stdio.h>
#include <stdlib.h>
#include "advent.h"
#include "advdec.h"
_PROTOTYPE(void descitem, (void));
_PROTOTYPE(void domove, (void));
_PROTOTYPE(void goback, (void));
_PROTOTYPE(void copytrv, (struct trav *, struct trav *));
_PROTOTYPE(void dotrav, (void));
_PROTOTYPE(void badmove, (void));
_PROTOTYPE(void spcmove, (int));
_PROTOTYPE(void death, (void));
_PROTOTYPE(void dwarves, (void));
_PROTOTYPE(void dopirate, (void));
_PROTOTYPE(int stimer, (void));
_PROTOTYPE(void do_hint, (int));
/*
Routine to take 1 turn
*/
void turn()
{
int i, hint;
static int waste = 0;
if (newtravel) {
/* If closing, then he can't leave except via the main office. */
if (outside(g.newloc) && g.newloc != 0 && g.closing) {
rspeak(130);
g.newloc = g.loc;
if (!g.panic)
g.clock2 = 15;
g.panic = TRUE;
}
/* See if a dwarf has seen him and has come from where he wants
to go. */
if (g.newloc != g.loc && !forced(g.loc) && g.loc_attrib[g.loc] & NOPIRAT == 0)
for (i = 1; i < (DWARFMAX - 1); ++i)
if (g.odloc[i] == g.newloc && g.dseen[i]) {
g.newloc = g.loc;
rspeak(2);
break;
}
g.loc = g.newloc;
dwarves(); /* & special dwarf(pirate who
steals) */
/* Check for death */
if (g.loc == 0) {
death();
return;
}
/* Check for forced move */
if (forced(g.loc)) {
desclg(g.loc);
++g.visited[g.loc];
domove();
return;
}
/* Check for wandering in dark */
if (g.wzdark && dark() && pct(35)) {
rspeak(23);
g.oldloc2 = g.loc;
death();
return;
}
/* see if he is wasting his batteies out in the open */
if (outside(g.loc) && g.prop[LAMP]) {
waste++;
if (waste > 11) {
rspeak(324);
waste = 0;
}
} else
waste = 0;
/* If wumpus is chasing stooge, see if wumpus gets him */
if (g.chase) {
g.chase++;
g.prop[WUMPUS] = g.chase / 2;
move(WUMPUS, g.loc);
if (g.chase >= 10) {
if (dark())
rspeak(270);
pspeak(WUMPUS, 5);
death();
return;
}
}
/* check for radiation poisoning. */
g.health += (outside(g.loc)) ? 3 : 1;
if (g.health > 100)
g.health = 100;
if (here(RADIUM) && (g.place[RADIUM] != -SHIELD || ajar(SHIELD)))
g.health -= 7;
if (g.health < 60) {
rspeak(391 + (60 - g.health) / 10);
if (g.health < 0) {
death();
return;
}
}
if ((g.oldloc == 188) && (g.loc != 188 && g.loc != 189)
&& (g.prop[BOOTH] == 1)) {
move(GNOME, 0);
g.prop[BOOTH] = 0;
}
/* Describe his situation */
describe();
if (!blind()) {
++g.visited[g.loc];
descitem();
}
} /* end of newtravel start for
second entry point */
/* Check if this location is eligible for any hints. If been here
long enough, branch to help section. Ignore "hints" < HNTMIN
(special stuff, see database notes. */
for (hint = HNTMIN; hint <= HNTMAX; hint++) {
if (g.hinted[hint])
continue;
if (g.loc_attrib[g.loc] / 256 != hint - 6)
g.hintlc[hint] = -1;
g.hintlc[hint]++;
if (g.hintlc[hint] >= g.hints[hint][1])
do_hint(hint);
}
if (g.closed) {
if (g.prop[OYSTER] < 0 && toting(OYSTER))
pspeak(OYSTER, 1);
for (i = 1; i < MAXOBJ; ++i)
if (toting(i) && g.prop[i] < 0)
g.prop[i] = -1 - g.prop[i];
}
g.wzdark = dark();
if (g.knfloc > 0 && g.knfloc != g.loc)
g.knfloc = 0;
++g.turns;
i = rand();
if (stimer()) /* as the grains of sand slip
by */
return;
while (!english()) /* retrieve player instructions */
;
vrbx = 1;
objx = objs[1] ? 1 : 0;
iobx = iobjs[1] ? 1 : 0;
verb = VAL(verbs[vrbx]);
do {
object = objx ? objs[objx] : 0;
iobj = iobx ? iobjs[iobx] : 0;
if (object && (objs[2] || iobjs[2])) {
pspeak(object, -1);
printf(" ");
}
switch (CLASS(verbs[vrbx])) {
case MOTION:
motion = verb;
domove();
break;
case NOUN:
bug(22);
case ACTION:
if (object || iobj)
trverb();
else
itverb();
break;
case MISC:
rspeak(verb);
if (verb == 51)
g.hinted[1] = TRUE;
break;
default:
bug(22);
}
if (objx) {
objx++;
if (objs[objx] == 0)
objx = 0;
}
if ((!objx || !objs[objx]) && iobx) {
iobx++;
if (iobjs[iobx] == 0)
iobx = 0;
if (iobx && iobjs[1])
objx = 1;
}
} while (objx || iobx);
return;
}
/*
Routine to describe current location
*/
void describe()
{
if (toting(BEAR))
rspeak(141);
if (dark())
rspeak(16);
else if ((g.terse && verb != LOOK) || g.visited[g.loc] % g.abbnum)
descsh(g.loc);
else
desclg(g.loc);
if (g.loc == 33 && pct(25) && !g.closing)
rspeak(8);
if (g.loc == 147 && !g.visited[g.loc])
rspeak(216);
return;
}
/*
Routine to describe visible items
*/
void descitem()
{
int i, state;
for (i = 1; i < MAXOBJ; ++i) {
if (at(i)) {
if (i == STEPS && toting(NUGGET))
continue;
if (g.prop[i] < 0) {
if (g.closed)
continue;
else {
g.prop[i] = 0;
if (i == RUG || i == CHAIN
|| i == SWORD || i == CASK)
g.prop[i] = 1;
if (i == CLOAK || i == RING)
g.prop[i] = 2;
--g.tally;
}
}
if (i == STEPS && g.loc == g.fixed[STEPS])
state = 1;
else
state = g.prop[i] % 8;
pspeak(i, state);
lookin(i);
}
}
/* If remaining treasures too elusive, zap his lamp */
if (g.tally == g.tally2 && g.tally != 0 && g.limit > 35)
g.limit = 35;
return;
}
/*
Routine to handle player's demise via
waking up the dwarves...
*/
void dwarfend()
{
rspeak(136);
normend();
return;
}
/*
normal end of game
*/
void normend()
{
score(FALSE);
gaveup = TRUE;
return;
}
/*
Routine to handle the passing on of one
of the player's incarnations...
*/
void death()
{
int yea, j;
if (!g.closing) {
if (g.limit < 0) {
rspeak(185);
normend();
return;
}
yea = yes(81 + g.numdie * 2, 82 + g.numdie * 2, 54);
if (++g.numdie >= MAXDIE || !yea)
normend();
if (g.chase) {
g.chase = FALSE;
g.prop[WUMPUS] = 0;
move(WUMPUS, 174);
}
if (toting(LAMP))
g.prop[LAMP] = 0;
for (j = 1; j < MAXOBJ; ++j) {
if (toting(j))
drop(j, j == LAMP ? 1 : g.oldloc2);
if (wearng(j)) {
g.prop[j] = 0;
bitoff(j, WEARBT);
}
}
g.newloc = 3;
g.oldloc = g.loc;
g.health = 100;
return;
}
/* Closing -- no resurrection... */
rspeak(131);
++g.numdie;
normend();
return;
}
/*
dwarf stuff.
*/
void dwarves()
{
int i, j, k, attack, stick, dtotal;
/* See if dwarves allowed here */
if (g.newloc == 0 || forced(g.newloc) || g.loc_attrib[g.newloc] & NOPIRAT)
return;
/* See if dwarves are active. */
if (!g.dflag) {
if (inside(g.newloc))
++g.dflag;
return;
}
/* If first close encounter (of 3rd kind) */
if (g.dflag == 1) {
if (!inside(g.newloc) || pct(85))
return;
++g.dflag;
/* kill 0, 1 or 2 of the dwarfs */
for (i = 1; i < 3; ++i)
if (pct(50))
g.dloc[(ranz(DWARFMAX - 1)) + 1] = 0;
/* If any of the survivors is at location, use alternate choise */
for (i = 1; i <= DWARFMAX; ++i) {
if (g.dloc[i] == g.newloc)
g.dloc[i] = g.daltloc;
g.odloc[i] = g.dloc[i];
}
rspeak(3);
drop(AXE, g.newloc);
return;
}
/* Things are in full swing. Move each dwarf at random, except if
he's seen us then he sticks with us. Dwarfs never go to
locations outside or meet the bear or following him into dead
end in maze. And of couse, dead dwarves don't do much of
anything. */
dtotal = attack = stick = 0;
for (i = 1; i <= DWARFMAX; ++i) {
if (g.dloc[i] == 0)
continue;
/* Move a dwarf at random. we don't have a matrix around to do
it as in the original version... */
do
j = ranz(106) + 15;
/* allowed area */
while (j == g.odloc[i] || j == g.dloc[i]
|| g.loc_attrib[j] & NOPIRAT);
if (j == 0)
bug(36);
g.odloc[i] = g.dloc[i];
g.dloc[i] = j;
g.dseen[i] = ((g.dseen[i] && inside(g.newloc))
|| g.dloc[i] == g.newloc
|| g.odloc[i] == g.newloc);
if (g.dseen[i]) {
g.dloc[i] = g.newloc;
if (i == DWARFMAX)
dopirate();
else {
++dtotal;
if (g.odloc[i] == g.dloc[i]) {
++attack;
if (g.knfloc >= 0)
g.knfloc = g.newloc;
if (ranz(1000) < (45 * (g.dflag - 2)))
++stick;
}
}
}
}
/* Now we know shat's happing, let's tell the poor sucker about it */
if (dtotal == 0)
return;
if (dtotal > 1)
printf("There are %d threatening little dwarves in the room with you!\n", dtotal);
else
rspeak(4);
if (attack == 0)
return;
if (g.dflag == 2)
++g.dflag;
if (attack > 1) {
printf("%d of them throw knives at you!!\n", attack);
k = 6;
} else {
rspeak(5);
k = 52;
}
if (stick <= 1) {
rspeak(stick + k);
if (stick == 0)
return;
} else
printf("%d of them get you !!!\n", stick);
g.oldloc2 = g.newloc;
death();
return;
}
/*
pirate stuff
*/
void dopirate()
{
int j;
boolean k;
if (g.newloc == g.chloc || g.prop[CHEST] >= 0)
return;
k = FALSE;
/* Pirate won't take pyramid from plover room or dark room (too
easy! ) */
for (j = 1; j < MAXOBJ; ++j)
if (treasr(j) && !(j == CASK && liq(CASK) == WINE)
&& !(j == PYRAMID && (g.newloc == g.place[PYRAMID]
|| g.newloc == g.place[EMERALD]))) {
if (toting(j) && athand(j))
goto stealit;
if (here(j))
k = TRUE;
}
if (g.tally == g.tally2 + 1 && k == FALSE && g.place[CHEST] == 0 &&
athand(LAMP) && g.prop[LAMP] == 1) {
rspeak(186);
move(CHEST, g.chloc);
move(MESSAGE, g.chloc2);
g.dloc[DWARFMAX] = g.chloc;
g.odloc[DWARFMAX] = g.chloc;
g.dseen[DWARFMAX] = 0;
return;
}
if (g.odloc[DWARFMAX] != g.dloc[DWARFMAX] && pct(30))
rspeak(127);
return;
stealit:
rspeak(128);
/* don't steal chest back from troll! */
if (g.place[MESSAGE] == 0)
move(CHEST, g.chloc);
move(MESSAGE, g.chloc2);
for (j = 1; j < MAXOBJ; ++j) {
if (!treasr(j) || !athand(j)
|| (j == PYRAMID &&
(g.newloc == plac[PYRAMID] || g.newloc == plac[EMERALD]))
|| (j == CASK && (liq(CASK) != WINE)))
continue;
if (enclosed(j))
extract(j);
if (wearng(j)) {
g.prop[j] = 0;
bitoff(j, WEARBT);
}
insert(j, CHEST);
}
g.dloc[DWARFMAX] = g.chloc;
g.odloc[DWARFMAX] = g.chloc;
g.dseen[DWARFMAX] = FALSE;
return;
}
/*
special time limit stuff...
*/
int stimer()
{
int i, spk;
static int clock3;
g.foobar = g.foobar > 0 ? -g.foobar : 0;
g.combo = g.combo > 0 ? -g.combo : 0;
if (g.turns > 310 && g.abbnum != 10000 && !g.terse)
rspeak(273);
/* Bump all the right clocks for reconning battery life and closing */
if (g.closed) {
clock3--;
if (clock3 == 0) {
g.prop[PHONE] = 0;
g.prop[BOOTH] = 0;
rspeak(284);
} else if (clock3 < -7) {
rspeak(254);
normend();
return (TRUE);
}
}
if (g.tally == 0 && inside(g.loc) && g.loc != Y2)
--g.clock;
if (g.clock == 0) {
/* Start closing the cave */
g.prop[GRATE] = 0;
biton(GRATE, LOCKBT);
bitoff(GRATE, OPENBT);
g.prop[FISSURE] = 0;
g.prop[TDOOR] = 0;
biton(TDOOR, LOCKBT);
bitoff(TDOOR, OPENBT);
g.prop[TDOOR2] = 0;
biton(TDOOR2, LOCKBT);
bitoff(TDOOR2, OPENBT);
for (i = 1; i <= DWARFMAX; ++i) {
g.dseen[i] = FALSE;
g.dloc[i] = 0;
}
move(TROLL, 0);
move((TROLL + MAXOBJ), 0);
move(TROLL2, plac[TROLL]);
move((TROLL2 + MAXOBJ), fixd[TROLL]);
juggle(CHASM);
if (g.prop[BEAR] != 3)
destroy(BEAR);
g.prop[CHAIN] = 0;
g.fixed[CHAIN] = 0;
g.prop[AXE] = 0;
g.fixed[AXE] = 0;
rspeak(129);
g.clock = -1;
g.closing = TRUE;
return (FALSE);
}
if (g.clock < 0)
--g.clock2;
if (g.clock2 == 0) {
/* Set up storage room... and close the cave... */
g.prop[BOTTLE] = put(BOTTLE, 115, 8);
g.holder[BOTTLE] = WATER;
g.place[WATER] = -BOTTLE;
g.hlink[WATER] = 0;
bitoff(BOTTLE, OPENBT);
g.prop[PLANT] = put(PLANT, 115, 0);
g.prop[OYSTER] = put(OYSTER, 115, 0);
g.prop[LAMP] = put(LAMP, 115, 0);
g.prop[ROD] = put(ROD, 115, 0);
g.prop[DWARF] = put(DWARF, 115, 0);
g.loc = 115;
g.oldloc = 115;
g.newloc = 115;
/* Leave the grate with normal (non-negative property). */
put(GRATE, 116, 0);
biton(GRATE, LOCKBT);
bitoff(GRATE, OPENBT);
g.prop[SNAKE] = put(SNAKE, 116, 1);
g.prop[BIRD] = put(BIRD, 116, 1);
g.prop[CAGE] = put(CAGE, 116, 0);
g.prop[ROD2] = put(ROD2, 116, 0);
g.prop[PILLOW] = put(PILLOW, 116, 0);
g.prop[BOOTH] = put(BOOTH, 116, -3);
g.fixed[BOOTH] = 115;
g.prop[PHONE] = put(PHONE, 212, -4);
g.prop[MIRROR] = put(MIRROR, 115, 0);
g.fixed[MIRROR] = 116;
g.prop[BOOK2] = put(BOOK2, 115, 0);
for (i = 1; i < MAXOBJ; ++i) {
if (toting(i) && enclosed(i))
extract(i);
if (toting(i))
destroy(i);
}
rspeak(132);
g.closed = TRUE;
clock3 = 20 + ranz(20);
newtravel = TRUE;
return (TRUE);
}
if (g.prop[LAMP] == 1)
--g.limit;
if (g.limit == 0) {
--g.limit;
g.prop[LAMP] = 0;
if (here(LAMP))
rspeak(184);
return (FALSE);
}
if (g.limit < 0 && outside(g.loc)) {
rspeak(185);
normend();
return (TRUE);
}
if (g.limit <= 40) {
if (g.lmwarn || !here(LAMP))
return (FALSE);
g.lmwarn = TRUE;
spk = 187;
if (g.prop[BATTERIES] == 1)
spk = 323;
if (g.place[BATTERIES] == 0)
spk = 183;
if (g.prop[VEND] == 1)
spk = 189;
rspeak(spk);
return (FALSE);
}
return (FALSE);
}
/* HINTS
come here if he's been long enough at required location(s)
for some unused hint, hint number is in variable "hint".
Branch to quick test for additional conditions, then
do neet stuff. If conditions are met and we want to offer
hint. Clear hintlc if no action is taken.
*/
#define MASE 1
#define DARK 2
#define WITT 3
#define H_SWORD 4
#define SLIDE 5
#define H_GRATE 6
#define H_BIRD 7
#define H_ELFIN 8
#define RNBOW 9
#define STYX 10
#define H_SNAKE 11
#define CASTLE 12
void do_hint(hint)
int hint;
{
g.hintlc[hint] = 0;
switch (hint + 1 - HNTMIN) {
case MASE:
if (!at(g.loc) && !at(g.oldloc)
&& !at(g.loc) && burden(0) > 1)
break;
else
return;
case DARK:
if (g.prop[EMERALD] != -1 && g.prop[PYRAMID] == -1)
break;
else
return;
case WITT:
break;
case H_SWORD:
if ((g.prop[SWORD] == 1 || g.prop[SWORD] == 5)
&& !toting(CROWN))
break;
else
return;
case SLIDE:
break;
case H_GRATE:
if (g.prop[GRATE] == 0 && !athand(KEYS))
break;
else
return;
case H_BIRD:
if (here(BIRD) && athand(ROD) && object == BIRD)
break;
else
return;
case H_ELFIN:
if (!g.visited[159])
break;
else
return;
case RNBOW:
if (!toting(SHOES) || g.visited[205])
break;
else
return;
case STYX:
if (!athand(LYRE) && g.prop[DOG] != 1)
break;
else
return;
case H_SNAKE:
if (here(SNAKE) && !here(BIRD))
break;
else
return;
case CASTLE:
break;
default:
printf(" TRYING TO PRINT HINT # %d\n", hint);
bug(27);
}
if (!yes(g.hints[hint][3], 0, 54))
return;
printf("\nI am prepared to give you a hint,");
printf(" but it will cost you %2d points\n", g.hints[hint][2]);
g.hinted[hint] = yes(175, g.hints[hint][4], 54);
if (g.hinted[hint] && g.limit > 30)
g.limit += 30 * g.hints[hint][2];
return;
}

749
commands/advent/utility.c Executable file
View file

@ -0,0 +1,749 @@
/*
Utility Routines
the next logical funtions describe attributes of objects.
(ajar, hinged, opaque, printd, treasr, vessel, wearng)
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "advent.h"
#include "advdec.h"
/*
ajar .TRUE. if item is container and is open or unhinged
*/
boolean ajar(item)
int item;
{
return ((bitset(g.obj_state[item], OPENBT))
|| (vessel(item) && !hinged(item)));
}
/*
at .TRUE. To tell if player is on either side of a two sided object.
*/
boolean at(item)
int item;
{
if (item < 1 || item > MAXOBJ)
return (FALSE);
else
return (g.place[item] == g.loc || g.fixed[item] == g.loc);
}
/*
athand .TRUE. if item readily reachable
it can be lying here, in hand or in open container.
*/
boolean athand(item)
int item;
{
int contnr;
boolean aaa;
contnr = -g.place[item];
aaa = enclosed(item) && ajar(contnr);
return ((g.place[item] == g.loc) || holding(item)
|| (aaa && ((g.place[contnr] == g.loc)
|| (toting(item) && holding(contnr)))));
}
/*
bitoff turns off (sets to 0) a bit in obj_state word
*/
void bitoff(obj, bit)
int obj, bit;
{
long val;
val = 1L << bit;
g.obj_state[obj] &= ~val;
}
/*
biton turns on (sets to 1) a bit in obj_state word
*/
void biton(obj, bit)
int obj, bit;
{
long val;
val = 1L << bit;
g.obj_state[obj] |= val;
}
/*
bitset .TRUE. if object_state has bit N set
*/
boolean bitset(state, bit)
long state;
int bit;
{
return (((state >> bit) & 1) == 1);
}
/*
blind .TRUE. if you can't see at this loc, (darkness of glare)
*/
boolean blind()
{
return (dark() || (g.loc == 200
&& athand(LAMP) && (g.prop[LAMP] == 1)));
}
/*
burden .. returns weight of items being carried
if obj=0, burden calculates the total weight of the adventurer's burden
including everything in all containers (except the boat) that he is
carring.
if object is a container, calculate the weight of everything inside
the container (including the container itself). Since donkey FORTRAN
isn't recursive, we will only calculate weight of contained containers
one level down. The only serious contained container would be the sack
The only thing we'll miss will be filled VS empty bottle or cage.
If object isn't a container, return its weight.
*/
int burden(obj)
int obj;
{
int i, sum, temp;
sum = 0;
if (obj == 0) {
for (i = 1; i < MAXOBJ; i++) {
if (toting(i) && (g.place[i] != -BOAT))
sum += g.weight[i];
}
} else {
if (obj != BOAT) {
sum = g.weight[obj];
temp = g.holder[obj];
while (temp != 0) {
sum += g.weight[temp];
temp = g.hlink[temp];
}
}
}
return (sum);
}
/*
Routine to carry an object
start toting an object, removing it from the list of things
at its former location. If object > MAXOBJ ( moving "FIXED"
or second loc), then don't change place.
*/
void carry(obj, where)
int obj, where;
{
int temp;
if (obj < MAXOBJ) {
if (g.place[obj] == -1)
return;
g.place[obj] = -1;
}
if (g.atloc[where] == obj)
g.atloc[where] = g.link[obj];
else {
temp = g.atloc[where];
while (g.link[temp] != obj) {
temp = g.link[temp];
if (temp == 0)
bug(35);
}
g.link[temp] = g.link[obj];
}
return;
}
/*
confuz generates some variant of "Don't understand that" message.
*/
int confuz()
{
int msg;
msg = 60;
if (pct(50))
msg = 61;
if (pct(33))
msg = 13;
if (pct(25))
msg = 347;
if (pct(20))
msg = 195;
return (msg);
}
/*
dark .TRUE. if there is no light here
*/
boolean dark()
{
return (!(g.loc_attrib[g.loc] & LIGHT) &&
(!g.prop[LAMP] || !athand(LAMP)));
}
/*
Routine to check for presence
of dwarves..
*/
int dcheck()
{
int i;
for (i = 1; i < (DWARFMAX); ++i)
if (g.dloc[i] == g.loc)
return (i);
return (0);
}
/*
dead .TRUE. if object is now dead
*/
boolean dead(obj)
int obj;
{
return (bitset(g.obj_state[obj], 10));
}
/*
drop Place an object at a given loc, prefixing it onto the atloc list.
*/
void drop(obj, where)
int obj, where;
{
if (obj > MAXOBJ)
g.fixed[obj - MAXOBJ] = where;
else
g.place[obj] = where;
if (where > 0) {
g.link[obj] = g.atloc[where];
g.atloc[where] = obj;
}
return;
}
/*
destroy Permanently eliminate "object" by moving it to
a non-existent location.
*/
void destroy(obj)
int obj;
{
move(obj, 0);
return;
}
/*
edible .TRUE. if obj can be eaten.
*/
boolean edible(obj)
int obj;
{
return (bitset(g.obj_state[obj], 7));
}
/*
enclosed .TRUE. If object is inside a container.
*/
boolean enclosed(item)
int item;
{
if (item < 1 || item > MAXOBJ)
return (FALSE);
else
return (g.place[item] < -1);
}
/*
extract remove "object" from a container.
origionally name "remove" but rename to avoid conflict with stdio.h
*/
void extract(obj)
int obj;
{
int contnr, temp;
contnr = -g.place[obj];
g.place[obj] = -1;
if (g.holder[contnr] == obj)
g.holder[contnr] = g.hlink[obj];
else {
temp = g.holder[contnr];
while (g.hlink[temp] != obj) {
temp = g.hlink[temp];
if (temp == 0)
bug(35);
}
g.hlink[temp] = g.hlink[obj];
}
return;
}
/*
forced To tell if a location will causes a forced move.
A forced location is one from which he is immediately bounced
to another. Normal use is for death (forced to location zero)
and for description of journey from on place to another.
*/
int forced(at_loc)
int at_loc;
{
return ((g.loc_attrib[at_loc] & 10) == 2);
}
/*
here .TRUE. If an item is at location or is being carried.
*/
boolean here(item)
int item;
{
return (g.place[item] == g.loc || toting(item));
}
/*
hinged .TRUE. If object can be opened or shut.
*/
boolean hinged(object)
int object;
{
return (bitset(g.obj_state[object], 1));
}
/*
holding .TRUE. If the object is being carried in hand.
*/
boolean holding(item)
int item;
{
if (item < 1 || item > MAXOBJ)
return (FALSE);
else
return (g.place[item] == -1);
}
/*
insert
*/
void insert(obj, contnr)
int obj, contnr;
{
int temp;
if (contnr == obj)
bug(32);
carry(obj, g.loc);
temp = g.holder[contnr];
g.holder[contnr] = obj;
g.hlink[obj] = temp;
g.place[obj] = -contnr;
}
/*
inside = .TRUE. If location is well within cave
*/
boolean inside(loc)
int loc;
{
return (!outside(loc) && !portal(loc));
}
/*
Juggle an object by picking it up and putting it down again,
The purpose being to get the object to the front of the chain
at its loc.
*/
void juggle(obj)
int obj;
{
int i, j;
i = g.place[obj];
j = g.fixed[obj];
move(obj, i);
move(obj + MAXOBJ, j);
return;
}
/*
Determine liquid in the vessel
*/
int liq(item)
int item;
{
int liquid;
if ((item == BOTTLE) || (item == CASK))
liquid = liq2(((int) g.prop[item] >> 1) & 7);
else
liquid = 0;
return (liquid);
}
/*
Determine type of liquid in vessel
*/
int liq2(liquid)
int liquid;
{
switch (liquid) {
case 4:
return (WATER);
case 5:
return (OIL);
case 6:
return (WINE);
default:
return (0); /* empty */
}
}
/*
Determine liquid at a location
*/
int liqloc(loc)
int loc;
{
return (liq2((int) ((g.loc_attrib[loc] >> 1) & 7)));
}
/*
living .TRUE. If object is living, bear for example
*/
boolean living(obj)
int obj;
{
return (bitset(g.obj_state[obj], 9));
}
/*
locked .TRUE. if lockable object is locked
*/
boolean locked(item)
int item;
{
return (bitset(g.obj_state[item], 4));
}
/*
locks .TRUE. if you can lock this object
*/
boolean locks(item)
int item;
{
return (bitset(g.obj_state[item], 3));
}
/*
LOOKIN list contents if obj is a container and is open or transparent.
*/
void lookin(contnr)
int contnr;
{
int temp;
boolean first_time;
if (vessel(contnr) && (ajar(contnr) || !opaque(contnr))) {
temp = g.holder[contnr];
first_time = TRUE;
while (temp != 0) {
if (first_time)
rspeak(360);
printf(" ");
pspeak(temp, -1);
temp = g.hlink[temp];
first_time = FALSE;
}
}
return;
}
/*
Routine to move an object
*/
void move(obj, where)
int obj, where;
{
int from;
if (obj > MAXOBJ)
from = g.fixed[obj - MAXOBJ];
else {
if (enclosed(obj))
extract(obj);
from = g.place[obj];
}
if ((from > 0) && (from < MAXOBJ * 2))
carry(obj, from);
drop(obj, where);
return;
}
/*
noway, generate's some variant of "can't do that" message.
*/
int noway()
{
int msg;
msg = 14;
if (pct(50))
msg = 110;
if (pct(33))
msg = 147;
if (pct(25))
msg = 250;
if (pct(20))
msg = 262;
if (pct(17))
msg = 25;
if (pct(14))
msg = 345;
if (pct(12))
msg = 346;
return (msg);
}
/*
opaque .TRUE. If obj is non-transparent container
*/
boolean opaque(obj)
int obj;
{
return (bitset(g.obj_state[obj], 6));
}
/*
outsid .TRUE. If location is outside the cave
*/
boolean outside(loc)
int loc;
{
return (bitset(g.loc_attrib[loc], 6));
}
/*
Routine true x% of the time. (x an integer from 0 to 100)
*/
int pct(x)
int x;
{
return (ranz(100) < x);
}
/*
plural .TRUE. if object is multiple objects
*/
boolean plural(obj)
int obj;
{
return (bitset(g.obj_state[obj], 13));
}
/*
portal .TRUE. If location is a cave entrance
*/
boolean portal(loc)
int loc;
{
return (bitset(g.loc_attrib[loc], 5));
}
/*
printed .TRUE. If object can be read.
*/
boolean printed(obj)
int obj;
{
return (bitset(g.obj_state[obj], 8));
}
/*
put is the same as move, except it returns a
value used to set the negated prop values
for the repository objects.
*/
int put(obj, where, pval)
int obj, where, pval;
{
move(obj, where);
return ((-1) - pval);
}
/*
RANZ
*/
int ranz(range)
int range;
{
return (rand() % range);
}
/*
small .TRUE. If object fits in sack or small container
*/
boolean small(obj)
int obj;
{
return (bitset(g.obj_state[obj], 5));
}
/*
toting .TRUE. If an item is being caried.
*/
int toting(item)
int item;
{
boolean aaa, bbb, ccc;
int contnr, outer, outer2;
contnr = -g.place[item];
outer = -g.place[contnr];
outer2 = -g.place[outer];
aaa = holding(contnr);
bbb = enclosed(contnr) && holding(outer);
ccc = enclosed(outer) && holding(outer2);
return (holding(item) || (enclosed(item) && (aaa || bbb || ccc)));
}
/*
treasr .TRUE. If object is valuable for points
*/
boolean treasr(obj)
int obj;
{
return (bitset(g.obj_state[obj], 14));
}
/*
vessel .TRUE. if object can hold a liquid
*/
boolean vessel(obj)
int obj;
{
return (bitset(g.obj_state[obj], 15));
}
/*
wearng .TRUE. If wearing obj
*/
boolean wearng(item)
int item;
{
return (bitset(g.obj_state[item], WEARBT));
}
/*
worn .TRUE. if object is being worn
*/
boolean worn(obj)
int obj;
{
return (bitset(g.obj_state[obj], 11));
}
static char *e_msg[] = {
"message line > 70 characters", /* 00 */
"null line in message", /* 01 */
"too many words of messages", /* 02 */
"too many travel options", /* 03 */
"too many vocabulary words", /* 04 */
"required vocabulary word not found", /* 05 */
"too many rtext or mtext messages", /* 06 */
"too many hints", /* 07 */
"location has loc_attrib bit being set twice", /* 08 */
"invalid section number in database", /* 09 */
"out of order locs or rspeak entries.", /* 10 */
"illegal motion word in travel table", /* 11 */
"** unused **.",/* 12 */
"unknown or illegal word in adjective table.", /* 13 */
"illegal word in prep/obj table", /* 14 */
"too many entries in prep/obj table", /* 15 */
"object has condition bit set twice", /* 16 */
"object number too large", /* 17 */
"too many entries in adjective/noun table.", /* 18 */
"** unused **.",/* 19 */
"special travel (500>l>300) exceeds goto list", /* 20 */
"ran off end of vocabulary table", /* 21 */
"verb class (n/1000) not between 1 and 3", /* 22 */
"intransitive action verb exceeds goto list", /* 23 */
"transitive action verb exceeds goto list", /* 24 */
"conditional travel entry with no alternative", /* 25 */
"location has no travel entries", /* 26 */
"hint number exceeds goto list", /* 27 */
"invalid month returned by date function", /* 28 */
"action verb 'leave' has no object.", /* 29 */
"preposition found in unexpected table", /* 30 */
"received an unexpected word terminator from a1toa5", /* 31 */
"trying to put a container into itself (tricky!)", /* 32 */
"unknown word class in getwds", /* 33 */
"** unused **.",/* 34 */
"trying to carry a non-existent object"}; /* 35 */
/*
Fatal error routine
*/
void bug(n)
unsigned int n;
{
if (n < 36 && *e_msg[n] != '*')
fprintf(stderr, "Fatal error, probable cause: %s\n", e_msg[n]);
else
fprintf(stderr, "Fatal error number %d - Unused error number!\n", n);
panic((char *) 0, TRUE);
}
/*
Prompt for input, strip leading and trailing spaces,
return &buf[first non-whitespace].
Does not return if end of input.
*/
char *
ask(prompt, buf, buflen)
char *prompt, *buf;
int buflen;
{
fputs(prompt, stdout);
fflush(stdout);
if (!fgets(buf, buflen, stdin))
panic("end of input", FALSE);
if (*buf) {
int c;
char *end = buf + strlen(buf);
if (end[-1] != '\n')
/* Skip to end of line */
while ((c = getchar()) != '\n' && c != EOF);
while (*buf && isspace(*buf))
buf++;
while (buf <= --end && isspace(*end))
*end = '\0';
}
return buf;
}
/*
save and abort
*/
void panic(msg, save)
char *msg;
boolean save;
{
fprintf(stderr, "\nPANIC: %s%s\n",
msg ? msg : "", save ? ". Save..." : msg ? "" : "aborting.");
if (save)
saveadv("advpanic.sav");
exit(EXIT_FAILURE);
}

2142
commands/advent/verb.c Executable file

File diff suppressed because it is too large Load diff

594
commands/advent/vocab.c Executable file
View file

@ -0,0 +1,594 @@
/*
look-up vocabulary word in lex-ordered table. words may have
two entries with different codes. if minimum acceptable type
= 0, then return minimum of different codes. last word CANNOT
have two entries(due to binary sort).
word is the word to look up.
type is the minimum acceptable value,
if != 0 return %1000
*/
#include <string.h>
#include <stdio.h>
#include "advent.h"
#include "advdec.h"
static _CONST struct wac wc[] = {
"\"spelunker\"", 1016,
"22", 2053,
"22", 3012,
"34", 2053,
"34", 3013,
"4-leafed", 5034,
"7", 2053,
"7", 3011,
"?", 3051,
"above", 29,
"abra", 3050,
"abracd", 3050,
"across", 42,
"alacaz", 3050,
"all", 1109,
"altar", 90,
"and", 6001,
"answer", 2035,
"anvil", 1091,
"ascend", 29,
"at", 4009,
"attack", 2012,
"awaken", 2029,
"awkward", 26,
"axe", 1028,
"back", 8,
"ball", 1120,
"barren", 40,
"bat", 1104,
"bats", 1104,
"batshit", 1104,
"batteries", 1039,
"beans", 1024,
"bear", 1035,
"bed", 16,
"bedquilt", 70,
"bee", 1087,
"beehive", 1097,
"bees", 1087,
"billboard", 1116,
"bird", 1101,
"bitch", 2048,
"black", 5006,
"blast", 2023,
"blow", 2036,
"blowup", 2023,
"boat", 1048,
"book", 1110,
"booth", 1093,
"bottle", 1020,
"box", 1055,
"brass", 5004,
"break", 2028,
"bridge", 89,
"brief", 2026,
"broken", 54,
"broom", 1114,
"brush", 1114,
"brush", 2054,
"building", 12,
"bumble", 1087,
"burn", 2047,
"cage", 1004,
"cake", 1107, /* value must be
mushrooms + 1 */
"cakes", 1107,
"call", 2038,
"calm", 2010,
"canister", 1118,
"canyon", 25,
"cape", 1047,
"capture", 2001,
"carpet", 1040,
"carry", 2001,
"carving", 1115,
"cask", 1071,
"catch", 2001,
"cave", 67,
"cavern", 73,
"chain", 1064,
"chalice", 1070,
"chant", 2003,
"chasm", 1021, /* troll bridge */
"chest", 1055,
"chimney", 78,
"clam", 1014,
"click", 85,
"climb", 56,
"cloak", 1047,
"close", 2006,
"clover", 1073,
"cobble", 18,
"coins", 1054,
"comb", 1096,
"complain", 2048,
"continue", 7,
"continue", 2011,
"crack", 33,
"crap", 3106,
"crap!", 3106,
"crawl", 17,
"cross", 69,
"crown", 1066,
"crystal", 5033,
"cup", 1070,
"cupcakes", 1107,
"d", 30,
"dark", 22,
"debris", 51,
"defile", 23,
"depression", 63,
"descend", 30,
"describe", 2052,
"detonate", 2023,
"devour", 2014,
"diagnose", 2051,
"dial", 2039,
"diamond", 1051,
"diamonds", 1051,
"dig", 3066,
"discard", 2002,
"disturb", 2029,
"doff", 2002,
"dog", 1098,
"dome", 35,
"don", 2033,
"door", 1041, /* giant door */
"down", 30,
"down", 4008,
"downstream", 5,
"downward", 30,
"dragon", 1031,
"drawing", 1029,
"drink", 2015,
"drop", 2002,
"droplet", 1075,
"dump", 2002,
"dust", 2054,
"dwarf", 1017,
"dwarves", 1017,
"e", 43,
"east", 43,
"eat", 2014,
"egg", 1056,
"eggs", 1056,
"elfin", 5019,
"emerald", 1059,
"empty", 2013,
"enter", 3,
"entrance", 64,
"everything", 1109,
"examine", 2052,
"excavate", 3066,
"exit", 11,
"explore", 2011,
"extinguish", 2008,
"fee", 2025,
"fee", 3001,
"feed", 2021,
"fie", 2025,
"fie", 3002,
"fight", 2012,
"figure", 1027,
"fill", 2022,
"find", 2019,
"fissure", 1012,
"fling", 2017,
"floor", 58,
"flower", 1046,
"flowers", 1046,
"foe", 2025,
"foe", 3003,
"follow", 2011,
"foo", 2025,
"foo", 3004,
"food", 1019,
"forcd", 1,
"forest", 6,
"fork", 77,
"forward", 7,
"fountain", 1103,
"four-leafed", 5034,
"free", 2002,
"fresh", 5010,
"from", 4005,
"fuck", 3079,
"fuck!", 3079,
"fum", 2025,
"fum", 3005,
"gate", 2058,
"get", 2044,
"geyser", 1037, /* same as volcano */
"giant", 27,
"giant", 5029,
"glowing", 5031,
"gnome", 1105,
"go", 2011,
"gold", 1050,
"golden", 5001,
"goto", 2011,
"grab", 2032,
"grail", 1070,
"grate", 1003,
"green", 5032,
"grey", 5032,
"gripe", 2048,
"grotto", 91,
"guano", 1104,
"gully", 13,
"h20", 1081,
"hall", 38,
"headlamp", 1002,
"health", 2051,
"heave", 2017,
"heels", 1067,
"help", 3051,
"hike", 2011,
"hill", 2,
"hit", 2034,
"hive", 1097,
"hocus", 3050,
"hole", 52,
"holy", 5021,
"honey", 1096,
"honeycomb", 1096,
"horn", 1052,
"hound", 1098,
"house", 12,
"hurl", 2017,
"i", 2020,
"ice", 88,
"ignite", 2023,
"in", 19,
"in", 4001,
"insert", 2045,
"inside", 19,
"inside", 4001,
"into", 4001,
"inventory", 2020,
"inward", 19,
"iron", 5011,
"issue", 1016,
"jar", 1020,
"jerk", 2032,
"jewelry", 1053,
"jewels", 1053,
"jump", 39,
"keep", 2001,
"keg", 1071,
"key", 1090,
"keys", 1102,
"kick", 2034,
"kill", 2012,
"knapsack", 1108,
"knife", 1018,
"knives", 1018,
"knoll", 81,
"l", 2052,
"lamp", 1002,
"lantern", 1002,
"lead", 5023,
"leaden", 5023,
"leap", 39,
"leather", 5024,
"leave", 11,
"leave", 2037,
"ledge", 83,
"left", 36,
"light", 1002,
"little", 5012,
"lock", 2049,
"look", 2052,
"lost", 3068,
"low", 24,
"lyre", 1068,
"machine", 1038,
"magazine", 1016,
"main", 76,
"map", 2057,
"message", 1036,
"metal", 5035,
"ming", 5016,
"mirror", 1023,
"mist", 3069,
"moss", 1040,
"mumble", 2003,
"mushroom", 1106,
"mushrooms", 1106,
"n", 45,
"ne", 47,
"nest", 1056,
"north", 45,
"northeast", 47,
"northwest", 50,
"nothing", 2005,
"nowhere", 21,
"nugget", 1050,
"null", 21,
"nw", 50,
"oak", 5022,
"oaken", 5022,
"off", 4006,
"office", 76,
"oil", 1083, /* in bottle */
"on", 4002,
"onto", 4002,
"onward", 7,
"open", 2004,
"opensesame", 3050,
"oriental", 72,
"out", 11,
"outdoors", 32,
"outside", 11,
"over", 41,
"oyster", 1015,
"pantry", 57,
"passage", 23,
"pause", 2030,
"pearl", 1061,
"persian", 5002,
"peruse", 2027,
"peyote", 1106,
"phone", 1094,
"phonebooth", 1094,
"phuce", 82,
"pick", 2041,
"pillow", 1010,
"pirate", 1030,
"pirloc", 2059,
"piss", 3107,
"piss!", 3107,
"pit", 31,
"placate", 2010,
"plant", 1024,
"platinum", 5017,
"play", 2040,
"plover", 71,
"plugh", 65,
"pocus", 3050,
"pole", 1009,
"pool", 80,
"poster", 1113,
"pottery", 1058,
"pound", 2034,
"pour", 2013,
"pray", 92,
"prayer", 92,
"proceed", 2011,
"pull", 2032,
"punch", 2034,
"put", 2042,
"pyramid", 1060,
"q", 2018,
"quartz", 5036,
"quit", 2018,
"radium", 1119,
"rare", 5018,
"ration", 1019,
"read", 2027,
"refill", 2022,
"release", 2002,
"remove", 2046,
"reply", 2035,
"report", 2048,
"reservoir", 75,
"restore", 2031,
"retreat", 8,
"return", 8,
"right", 37,
"ring", 1072,
"road", 2,
"rock", 1119,
"rock", 15,
"rocks", 1092,
"rocks", 1115,
"rod", 1005,
"room", 59,
"rowboat", 1048,
"rub", 2016,
"ruby", 5020,
"rug", 1062,
"run", 2011,
"rusty", 5028,
"s", 46,
"sack", 1108,
"safe", 1112,
"saint-michel", 93,
"sandwich", 1019,
"sapphire", 1069,
"save", 2030,
"say", 2003,
"score", 2024,
"se", 48,
"secret", 66,
"sesame", 3050,
"shadowy", 5027,
"shake", 2009,
"shards", 1058,
"shatter", 2028,
"shazam", 3050,
"shelf", 83,
"shell", 74,
"shield", 1118,
"ship", 1048,
"shit", 3106,
"shit!", 3106,
"shoes", 1067,
"shut", 2006,
"silk", 5013,
"silken", 5013,
"silver", 5014,
"sing", 2003,
"slab", 61,
"slabroom", 61,
"slay", 2012,
"slide", 79,
"slippers", 1067,
"slit", 60,
"slugs", 1095,
"small", 5012,
"smash", 2028,
"snake", 1011,
"south", 46,
"southeast", 48,
"southwest", 49,
"spelunker", 1016,
"sphere", 1120,
"spices", 1063,
"stair", 10,
"stairs", 10,
"stalagmite", 1026,
"star", 5026,
"statue", 1074,
"steal", 2001,
"steel", 5025,
"steps", 1007,
"steps", 34,
"stick", 1049,
"sticks", 1049,
"stone", 1119,
"stop", 3139,
"stream", 14,
"strike", 2034,
"strum", 2040,
"suggest", 2048,
"surface", 20,
"suspend", 2030,
"sw", 49,
"sweep", 2054,
"swim", 3147,
"swing", 2009,
"sword", 1065,
"tablet", 1013,
"take", 2001,
"tame", 2010,
"tasty", 5030,
"telephone", 1094,
"terse", 2055,
"then", 6002,
"throw", 2017,
"thunder", 84,
"tiny", 5012,
"to", 4004,
"tome", 1110,
"toss", 2017,
"tote", 2001,
"travel", 2011,
"treasure", 5015,
"tree", 1074,
"tree", 3064,
"trees", 3064,
"trident", 1057,
"troll", 1033,
"tube", 1118,
"tunnel", 23,
"turn", 2043,
"u", 29,
"unbrief", 2026,
"unlock", 2050,
"unterse", 2055,
"up", 29,
"up", 4007,
"upon", 4002,
"upstream", 4,
"upward", 29,
"used", 5009,
"utter", 2003,
"valley", 9,
"vase", 1058,
"velvet", 5007,
"vending", 5008,
"view", 28,
"volcano", 1037,
"volume", 1110,
"w", 44,
"wake", 2029,
"waken", 2029,
"walk", 2011,
"wall", 53,
"wall", 1088, /* in blue grotto */
"wand", 1005,
"water", 1081, /* in bottle */
"wave", 2009,
"wear", 2033,
"west", 44,
"whack", 2034,
"where", 2019,
"whirl", 80,
"whirlpool", 80,
"whisk", 1114,
"whiskbroom", 1114,
"wicker", 5005,
"wine", 1085, /* in bottle */
"with", 4003,
"wiz", 2056,
"wolf", 1098,
"wooden", 5003,
"worn", 5009,
"worn-out", 5009,
"wornout", 5009,
"wumpus", 1099,
"xyzzy", 62,
"y2", 55,
"yank", 2032
};
#define MAXWC (sizeof(wc) / sizeof(struct wac))
_PROTOTYPE(int binary, (char *));
int vocab(word, type)
char *word;
int type;
{
int v1, v2, temp;
if ((v1 = binary(word)) >= 0) {
if (v1 > 0 && strcmp(word, wc[v1 - 1].aword) == 0)
v2 = v1 - 1;
else if (v1 < (MAXWC - 1) && strcmp(word, wc[v1 + 1].aword) == 0)
v2 = v1 + 1;
else
v2 = v1;
if (wc[v1].acode > wc[v2].acode) {
temp = v1;
v1 = v2;
v2 = temp;
}
if (type <= CLASS(wc[v1].acode))
return (wc[v1].acode);
else if (type <= CLASS(wc[v2].acode))
return (wc[v2].acode);
else
return (-1);
} else
return (-1);
}
int binary(w)
char *w;
{
int lo, mid, hi, check;
lo = 0;
hi = MAXWC - 1;
do {
mid = (lo + hi) / 2;
check = strcmp(w, wc[mid].aword);
if (check == 0)
return (mid);
else if (check < 0)
hi = mid - 1;
else
lo = mid + 1;
} while (lo <= hi);
return (-1);
}

101
commands/ash/Makefile Executable file
View file

@ -0,0 +1,101 @@
# Makefile for ash.
SRCS= builtins.c cd.c dirent.c error.c eval.c exec.c expand.c input.c \
jobs.c mail.c main.c memalloc.c miscbltin.c mystring.c nodes.c \
options.c parser.c redir.c show.c signames.c syntax.c trap.c \
output.c var.c
OBJS= builtins.o cd.o dirent.o error.o eval.o exec.o expand.o input.o \
jobs.o mail.o main.o memalloc.o miscbltin.o mystring.o nodes.o \
options.o parser.o redir.o show.o signames.o syntax.o trap.o \
output.o var.o init.o \
bltin/echo.o bltin/expr.o bltin/operators.o bltin/regexp.o
#
# Set READLINE in shell.h and add -ledit to LIBS if you want to use the
# editline package by Simmule Turner and Rich Salz. (The big, bloated
# and GPL contaminated FSF readline should work too.)
#
CPPFLAGS= -DSHELL -I. -D_MINIX -D_POSIX_SOURCE
CFLAGS= -wo -i $(CPPFLAGS)
LIBS= -ledit
CLEANFILES= $(OBJS) \
builtins.c builtins.h init.c mkinit mknodes mksignames mksyntax \
nodes.c nodes.h signames.c signames.h syntax.c syntax.h token.def \
bltin/operators.h bltin/operators.c
all: sh
sh: $(OBJS)
$(CC) $(CFLAGS) -o sh $(OBJS) $(LIBS)
install -S 12kw sh
install: /usr/bin/ash /usr/bin/sh /bin/sh
/usr/bin/ash: sh
install -cs -o bin $? $@
/usr/bin/sh: /usr/bin/ash
install -l $? $@
/bin/sh: /usr/bin/ash
install -lcs $? $@
clean:
rm -f $(CLEANFILES) sh core
parser.o: token.def
token.def: mktokens
sh mktokens
builtins.c builtins.h: builtins.table shell.h
sh mkbuiltins shell.h builtins.table
init.o: mkinit $(SRCS)
./mkinit '$(CC) -c $(CFLAGS) init.c' $(SRCS)
mkinit: mkinit.c
$(CC) $(CFLAGS) mkinit.c -o $@
nodes.c nodes.h: mknodes nodetypes nodes.c.pat
./mknodes nodetypes nodes.c.pat
mknodes: mknodes.c
$(CC) $(CFLAGS) mknodes.c -o $@
signames.c signames.h: mksignames
./mksignames
mksignames: mksignames.c
$(CC) $(CFLAGS) mksignames.c -o $@
syntax.c syntax.h: mksyntax
./mksyntax
mksyntax: mksyntax.c parser.h
$(CC) $(CFLAGS) mksyntax.c -o $@
bltin/operators.h: bltin/mkexpr bltin/binary_op bltin/unary_op
cd bltin && sh mkexpr
bltin/echo.o: bltin/echo.c
cd bltin && $(CC) -I.. $(CFLAGS) -c echo.c
bltin/expr.o: bltin/expr.c
cd bltin && $(CC) -I.. $(CFLAGS) -c expr.c
bltin/operators.o: bltin/operators.c
cd bltin && $(CC) -I.. $(CFLAGS) -c operators.c
bltin/regexp.o: bltin/regexp.c
cd bltin && $(CC) -I.. $(CFLAGS) -c regexp.c
# Dependencies you say? This will have to do.
$(OBJS): error.h eval.h exec.h expand.h init.h input.h \
jobs.h machdep.h mail.h main.h memalloc.h mystring.h options.h \
output.h parser.h redir.h shell.h trap.h var.h \
builtins.h nodes.h signames.h syntax.h
bltin/expr.o bltin/operators.o: bltin/operators.h

348
commands/ash/TOUR Executable file
View file

@ -0,0 +1,348 @@
# @(#)TOUR 5.1 (Berkeley) 3/7/91
A Tour through Ash
Copyright 1989 by Kenneth Almquist.
DIRECTORIES: The subdirectory bltin contains commands which can
be compiled stand-alone. The rest of the source is in the main
ash directory.
SOURCE CODE GENERATORS: Files whose names begin with "mk" are
programs that generate source code. A complete list of these
programs is:
program intput files generates
------- ------------ ---------
mkbuiltins builtins builtins.h builtins.c
mkinit *.c init.c
mknodes nodetypes nodes.h nodes.c
mksignames - signames.h signames.c
mksyntax - syntax.h syntax.c
mktokens - token.def
bltin/mkexpr unary_op binary_op operators.h operators.c
There are undoubtedly too many of these. Mkinit searches all the
C source files for entries looking like:
INIT {
x = 1; /* executed during initialization */
}
RESET {
x = 2; /* executed when the shell does a longjmp
back to the main command loop */
}
SHELLPROC {
x = 3; /* executed when the shell runs a shell procedure */
}
It pulls this code out into routines which are when particular
events occur. The intent is to improve modularity by isolating
the information about which modules need to be explicitly
initialized/reset within the modules themselves.
Mkinit recognizes several constructs for placing declarations in
the init.c file.
INCLUDE "file.h"
includes a file. The storage class MKINIT makes a declaration
available in the init.c file, for example:
MKINIT int funcnest; /* depth of function calls */
MKINIT alone on a line introduces a structure or union declara-
tion:
MKINIT
struct redirtab {
short renamed[10];
};
Preprocessor #define statements are copied to init.c without any
special action to request this.
INDENTATION: The ash source is indented in multiples of six
spaces. The only study that I have heard of on the subject con-
cluded that the optimal amount to indent is in the range of four
to six spaces. I use six spaces since it is not too big a jump
from the widely used eight spaces. If you really hate six space
indentation, use the adjind (source included) program to change
it to something else.
EXCEPTIONS: Code for dealing with exceptions appears in
exceptions.c. The C language doesn't include exception handling,
so I implement it using setjmp and longjmp. The global variable
exception contains the type of exception. EXERROR is raised by
calling error. EXINT is an interrupt. EXSHELLPROC is an excep-
tion which is raised when a shell procedure is invoked. The pur-
pose of EXSHELLPROC is to perform the cleanup actions associated
with other exceptions. After these cleanup actions, the shell
can interpret a shell procedure itself without exec'ing a new
copy of the shell.
INTERRUPTS: In an interactive shell, an interrupt will cause an
EXINT exception to return to the main command loop. (Exception:
EXINT is not raised if the user traps interrupts using the trap
command.) The INTOFF and INTON macros (defined in exception.h)
provide uninterruptable critical sections. Between the execution
of INTOFF and the execution of INTON, interrupt signals will be
held for later delivery. INTOFF and INTON can be nested.
MEMALLOC.C: Memalloc.c defines versions of malloc and realloc
which call error when there is no memory left. It also defines a
stack oriented memory allocation scheme. Allocating off a stack
is probably more efficient than allocation using malloc, but the
big advantage is that when an exception occurs all we have to do
to free up the memory in use at the time of the exception is to
restore the stack pointer. The stack is implemented using a
linked list of blocks.
STPUTC: If the stack were contiguous, it would be easy to store
strings on the stack without knowing in advance how long the
string was going to be:
p = stackptr;
*p++ = c; /* repeated as many times as needed */
stackptr = p;
The folloing three macros (defined in memalloc.h) perform these
operations, but grow the stack if you run off the end:
STARTSTACKSTR(p);
STPUTC(c, p); /* repeated as many times as needed */
grabstackstr(p);
We now start a top-down look at the code:
MAIN.C: The main routine performs some initialization, executes
the user's profile if necessary, and calls cmdloop. Cmdloop is
repeatedly parses and executes commands.
OPTIONS.C: This file contains the option processing code. It is
called from main to parse the shell arguments when the shell is
invoked, and it also contains the set builtin. The -i and -j op-
tions (the latter turns on job control) require changes in signal
handling. The routines setjobctl (in jobs.c) and setinteractive
(in trap.c) are called to handle changes to these options.
PARSING: The parser code is all in parser.c. A recursive des-
cent parser is used. Syntax tables (generated by mksyntax) are
used to classify characters during lexical analysis. There are
three tables: one for normal use, one for use when inside single
quotes, and one for use when inside double quotes. The tables
are machine dependent because they are indexed by character vari-
ables and the range of a char varies from machine to machine.
PARSE OUTPUT: The output of the parser consists of a tree of
nodes. The various types of nodes are defined in the file node-
types.
Nodes of type NARG are used to represent both words and the con-
tents of here documents. An early version of ash kept the con-
tents of here documents in temporary files, but keeping here do-
cuments in memory typically results in significantly better per-
formance. It would have been nice to make it an option to use
temporary files for here documents, for the benefit of small
machines, but the code to keep track of when to delete the tem-
porary files was complex and I never fixed all the bugs in it.
(AT&T has been maintaining the Bourne shell for more than ten
years, and to the best of my knowledge they still haven't gotten
it to handle temporary files correctly in obscure cases.)
The text field of a NARG structure points to the text of the
word. The text consists of ordinary characters and a number of
special codes defined in parser.h. The special codes are:
CTLVAR Variable substitution
CTLENDVAR End of variable substitution
CTLBACKQ Command substitution
CTLBACKQ|CTLQUOTE Command substitution inside double quotes
CTLESC Escape next character
A variable substitution contains the following elements:
CTLVAR type name '=' [ alternative-text CTLENDVAR ]
The type field is a single character specifying the type of sub-
stitution. The possible types are:
VSNORMAL $var
VSMINUS ${var-text}
VSMINUS|VSNUL ${var:-text}
VSPLUS ${var+text}
VSPLUS|VSNUL ${var:+text}
VSQUESTION ${var?text}
VSQUESTION|VSNUL ${var:?text}
VSASSIGN ${var=text}
VSASSIGN|VSNUL ${var=text}
In addition, the type field will have the VSQUOTE flag set if the
variable is enclosed in double quotes. The name of the variable
comes next, terminated by an equals sign. If the type is not
VSNORMAL, then the text field in the substitution follows, ter-
minated by a CTLENDVAR byte.
Commands in back quotes are parsed and stored in a linked list.
The locations of these commands in the string are indicated by
CTLBACKQ and CTLBACKQ+CTLQUOTE characters, depending upon whether
the back quotes were enclosed in double quotes.
The character CTLESC escapes the next character, so that in case
any of the CTL characters mentioned above appear in the input,
they can be passed through transparently. CTLESC is also used to
escape '*', '?', '[', and '!' characters which were quoted by the
user and thus should not be used for file name generation.
CTLESC characters have proved to be particularly tricky to get
right. In the case of here documents which are not subject to
variable and command substitution, the parser doesn't insert any
CTLESC characters to begin with (so the contents of the text
field can be written without any processing). Other here docu-
ments, and words which are not subject to splitting and file name
generation, have the CTLESC characters removed during the vari-
able and command substitution phase. Words which are subject
splitting and file name generation have the CTLESC characters re-
moved as part of the file name phase.
EXECUTION: Command execution is handled by the following files:
eval.c The top level routines.
redir.c Code to handle redirection of input and output.
jobs.c Code to handle forking, waiting, and job control.
exec.c Code to to path searches and the actual exec sys call.
expand.c Code to evaluate arguments.
var.c Maintains the variable symbol table. Called from expand.c.
EVAL.C: Evaltree recursively executes a parse tree. The exit
status is returned in the global variable exitstatus. The alter-
native entry evalbackcmd is called to evaluate commands in back
quotes. It saves the result in memory if the command is a buil-
tin; otherwise it forks off a child to execute the command and
connects the standard output of the child to a pipe.
JOBS.C: To create a process, you call makejob to return a job
structure, and then call forkshell (passing the job structure as
an argument) to create the process. Waitforjob waits for a job
to complete. These routines take care of process groups if job
control is defined.
REDIR.C: Ash allows file descriptors to be redirected and then
restored without forking off a child process. This is accom-
plished by duplicating the original file descriptors. The redir-
tab structure records where the file descriptors have be dupli-
cated to.
EXEC.C: The routine find_command locates a command, and enters
the command in the hash table if it is not already there. The
third argument specifies whether it is to print an error message
if the command is not found. (When a pipeline is set up,
find_command is called for all the commands in the pipeline be-
fore any forking is done, so to get the commands into the hash
table of the parent process. But to make command hashing as
transparent as possible, we silently ignore errors at that point
and only print error messages if the command cannot be found
later.)
The routine shellexec is the interface to the exec system call.
EXPAND.C: Arguments are processed in three passes. The first
(performed by the routine argstr) performs variable and command
substitution. The second (ifsbreakup) performs word splitting
and the third (expandmeta) performs file name generation. If the
"/u" directory is simulated, then when "/u/username" is replaced
by the user's home directory, the flag "didudir" is set. This
tells the cd command that it should print out the directory name,
just as it would if the "/u" directory were implemented using
symbolic links.
VAR.C: Variables are stored in a hash table. Probably we should
switch to extensible hashing. The variable name is stored in the
same string as the value (using the format "name=value") so that
no string copying is needed to create the environment of a com-
mand. Variables which the shell references internally are preal-
located so that the shell can reference the values of these vari-
ables without doing a lookup.
When a program is run, the code in eval.c sticks any environment
variables which precede the command (as in "PATH=xxx command") in
the variable table as the simplest way to strip duplicates, and
then calls "environment" to get the value of the environment.
There are two consequences of this. First, if an assignment to
PATH precedes the command, the value of PATH before the assign-
ment must be remembered and passed to shellexec. Second, if the
program turns out to be a shell procedure, the strings from the
environment variables which preceded the command must be pulled
out of the table and replaced with strings obtained from malloc,
since the former will automatically be freed when the stack (see
the entry on memalloc.c) is emptied.
BUILTIN COMMANDS: The procedures for handling these are scat-
tered throughout the code, depending on which location appears
most appropriate. They can be recognized because their names al-
ways end in "cmd". The mapping from names to procedures is
specified in the file builtins, which is processed by the mkbuil-
tins command.
A builtin command is invoked with argc and argv set up like a
normal program. A builtin command is allowed to overwrite its
arguments. Builtin routines can call nextopt to do option pars-
ing. This is kind of like getopt, but you don't pass argc and
argv to it. Builtin routines can also call error. This routine
normally terminates the shell (or returns to the main command
loop if the shell is interactive), but when called from a builtin
command it causes the builtin command to terminate with an exit
status of 2.
The directory bltins contains commands which can be compiled in-
dependently but can also be built into the shell for efficiency
reasons. The makefile in this directory compiles these programs
in the normal fashion (so that they can be run regardless of
whether the invoker is ash), but also creates a library named
bltinlib.a which can be linked with ash. The header file bltin.h
takes care of most of the differences between the ash and the
stand-alone environment. The user should call the main routine
"main", and #define main to be the name of the routine to use
when the program is linked into ash. This #define should appear
before bltin.h is included; bltin.h will #undef main if the pro-
gram is to be compiled stand-alone.
CD.C: This file defines the cd and pwd builtins. The pwd com-
mand runs /bin/pwd the first time it is invoked (unless the user
has already done a cd to an absolute pathname), but then
remembers the current directory and updates it when the cd com-
mand is run, so subsequent pwd commands run very fast. The main
complication in the cd command is in the docd command, which
resolves symbolic links into actual names and informs the user
where the user ended up if he crossed a symbolic link.
SIGNALS: Trap.c implements the trap command. The routine set-
signal figures out what action should be taken when a signal is
received and invokes the signal system call to set the signal ac-
tion appropriately. When a signal that a user has set a trap for
is caught, the routine "onsig" sets a flag. The routine dotrap
is called at appropriate points to actually handle the signal.
When an interrupt is caught and no trap has been set for that
signal, the routine "onint" in error.c is called.
OUTPUT: Ash uses it's own output routines. There are three out-
put structures allocated. "Output" represents the standard out-
put, "errout" the standard error, and "memout" contains output
which is to be stored in memory. This last is used when a buil-
tin command appears in backquotes, to allow its output to be col-
lected without doing any I/O through the UNIX operating system.
The variables out1 and out2 normally point to output and errout,
respectively, but they are set to point to memout when appropri-
ate inside backquotes.
INPUT: The basic input routine is pgetc, which reads from the
current input file. There is a stack of input files; the current
input file is the top file on this stack. The code allows the
input to come from a string rather than a file. (This is for the
-c option and the "." and eval builtin commands.) The global
variable plinno is saved and restored when files are pushed and
popped from the stack. The parser routines store the number of
the current line in this variable.
DEBUGGING: If DEBUG is defined in shell.h, then the shell will
write debugging information to the file $HOME/trace. Most of
this is done using the TRACE macro, which takes a set of printf
arguments inside two sets of parenthesis. Example:
"TRACE(("n=%d0, n))". The double parenthesis are necessary be-
cause the preprocessor can't handle functions with a variable
number of arguments. Defining DEBUG also causes the shell to
generate a core dump if it is sent a quit signal. The tracing
code is in show.c.

40
commands/ash/bltin/LICENSE Executable file
View file

@ -0,0 +1,40 @@
ASH GENERAL PUBLIC LICENSE
1. You may copy and distribute ash code or code derived from it in
source or object form, provided that you conspicuously and appropriately
publish on each copy a valid copyright notice "Copyright 1989 by Kenneth
Almquist." (or with whatever year is appropriate); keep intact the
notices on all files that refer to this License Agreement and to the
absence of any warranty; and give any other recipients of the ash program
a copy of this License Agreement along with the program.
2. You may not copy, sublicense, distribute or transfer ash except as
expressly provided under this License Agreement. Any attempt otherwise
to copy, sublicense, distribute or transfer ash is void and your rights
to use ash under this License agreement shall be automatically terminated.
However, parties who have received computer software programs from you
with this License Agreement will not have their licenses terminated so
long as such parties remain in full compliance.
NO WARRANTY
Because ash is licensed free of charge, I provide absolutely no
warranty, to the extent permitted by applicable state law. Except
when otherwise stated in writing, Kenneth Almquist and/or other
parties provide ash "as is" without warranty of any kind, either
expressed or implied, including, but not limited to, the implied
warranties of merchantability and fitness for a particular purpose.
The entire risk as to the quality and performance of the program is
with you. Should the ash program prove defective, you assume the cost
of all necessary servicing, repair or correction.
In no event unless required by applicable law will Kenneth Almquist
and/or any other party who may modify and redistribute ash as permitted
above, be liable to you for damages, including any lost profits, lost
monies, or other special, incidental or consequential damages arising
out of the use or inability to use (including but not limited to loss
of data or data being rendered inaccurate or losses sustained by third
parties or a failure of the program to operate with programs provided
by other parties) the program, even if you have been advised of the
possibility of such damages, or for any claim by any other party.

25
commands/ash/bltin/binary_op Executable file
View file

@ -0,0 +1,25 @@
# List of binary operators used by test/expr.
#
# Copyright 1989 by Kenneth Almquist. All rights reserved.
# This file is part of ash, which is distributed under the terms specified
# by the Ash General Public License. See the file named LICENSE.
OR1 -o 1
OR2 | 1
AND1 -a 2
AND2 & 2
STREQ = 4 OP_STRING
STRNE != 4 OP_STRING
NEWER -newer 4 OP_STRING
EQ -eq 4 OP_INT
NE -ne 4 OP_INT
GT -gt 4 OP_INT
LT -lt 4 OP_INT
LE -le 4 OP_INT
GE -ge 4 OP_INT
PLUS + 5 OP_INT
MINUS - 5 OP_INT
TIMES * 6 OP_INT
DIVIDE / 6 OP_INT
REM % 6 OP_INT
MATCHPAT : 7 OP_STRING

40
commands/ash/bltin/bltin.h Executable file
View file

@ -0,0 +1,40 @@
/*
* This file is included by programs which are optionally built into the
* shell. If SHELL is defined, we try to map the standard UNIX library
* routines to ash routines using defines.
*
* Copyright (C) 1989 by Kenneth Almquist. All rights reserved.
* This file is part of ash, which is distributed under the terms specified
* by the Ash General Public License. See the file named LICENSE.
*/
#include "../shell.h"
#include "../mystring.h"
#ifdef SHELL
#include "../output.h"
#define stdout out1
#define stderr out2
#define printf out1fmt
#define putc(c, file) outc(c, file)
#define putchar(c) out1c(c)
#define fprintf outfmt
#define fputs outstr
#define fflush flushout
#define INITARGS(argv)
#else
#undef NULL
#include <stdio.h>
#undef main
#define INITARGS(argv) if ((commandname = argv[0]) == NULL) {fputs("Argc is zero\n", stderr); exit(2);} else
#endif
#ifdef __STDC__
pointer stalloc(int);
void error(char *, ...);
#else
pointer stalloc();
void error();
#endif
extern char *commandname;

88
commands/ash/bltin/catf.c Executable file
View file

@ -0,0 +1,88 @@
/*
* Copy the files given as arguments to the standard output. The file
* name "-" refers to the standard input.
*
* Copyright (C) 1989 by Kenneth Almquist. All rights reserved.
* This file is part of ash, which is distributed under the terms specified
* by the Ash General Public License. See the file named LICENSE.
*/
#define main catfcmd
#include "bltin.h"
#include "../error.h"
#include <sys/param.h>
#include <fcntl.h>
#ifdef SBUFSIZE
#define BUFSIZE() SBUFSIZE
#else
#ifdef MAXBSIZE
#define BUFSIZE() MAXBSIZE
#else
#define BUFSIZE() BSIZE
#endif
#endif
main(argc, argv) char **argv; {
char *filename;
char *buf = stalloc(BUFSIZE());
int fd;
int i;
#ifdef SHELL
volatile int input;
struct jmploc jmploc;
struct jmploc *volatile savehandler;
#endif
INITARGS(argv);
#ifdef SHELL
input = -1;
if (setjmp(jmploc.loc)) {
close(input);
handler = savehandler;
longjmp(handler, 1);
}
savehandler = handler;
handler = &jmploc;
#endif
while ((filename = *++argv) != NULL) {
if (filename[0] == '-' && filename[1] == '\0') {
fd = 0;
} else {
#ifdef SHELL
INTOFF;
if ((fd = open(filename, O_RDONLY)) < 0)
error("Can't open %s", filename);
input = fd;
INTON;
#else
if ((fd = open(filename, O_RDONLY)) < 0) {
fprintf(stderr, "catf: Can't open %s\n", filename);
exit(2);
}
#endif
}
while ((i = read(fd, buf, BUFSIZE())) > 0) {
#ifdef SHELL
if (out1 == &memout) {
register char *p;
for (p = buf ; --i >= 0 ; p++) {
outc(*p, &memout);
}
} else {
write(1, buf, i);
}
#else
write(1, buf, i);
#endif
}
if (fd != 0)
close(fd);
}
#ifdef SHELL
handler = savehandler;
#endif
}

74
commands/ash/bltin/echo.c Executable file
View file

@ -0,0 +1,74 @@
/*
* Echo command.
*
* Copyright (C) 1989 by Kenneth Almquist. All rights reserved.
* This file is part of ash, which is distributed under the terms specified
* by the Ash General Public License. See the file named LICENSE.
*/
#define main echocmd
#include "bltin.h"
#undef eflag
main(argc, argv) char **argv; {
register char **ap;
register char *p;
register char c;
int count;
int nflag = 0;
#ifndef eflag
int eflag = 0;
#endif
ap = argv;
if (argc)
ap++;
if ((p = *ap) != NULL) {
if (equal(p, "--")) {
ap++;
}
if (equal(p, "-n")) {
nflag++;
ap++;
} else if (equal(p, "-e")) {
#ifndef eflag
eflag++;
#endif
ap++;
}
}
while ((p = *ap++) != NULL) {
while ((c = *p++) != '\0') {
if (c == '\\' && eflag) {
switch (*p++) {
case 'b': c = '\b'; break;
case 'c': return 0; /* exit */
case 'f': c = '\f'; break;
case 'n': c = '\n'; break;
case 'r': c = '\r'; break;
case 't': c = '\t'; break;
case 'v': c = '\v'; break;
case '\\': break; /* c = '\\' */
case '0':
c = 0;
count = 3;
while (--count >= 0 && (unsigned)(*p - '0') < 8)
c = (c << 3) + (*p++ - '0');
break;
default:
p--;
break;
}
}
putchar(c);
}
if (*ap)
putchar(' ');
}
if (! nflag)
putchar('\n');
return 0;
}

23
commands/ash/bltin/error.c Executable file
View file

@ -0,0 +1,23 @@
/*
* Copyright (C) 1989 by Kenneth Almquist. All rights reserved.
* This file is part of ash, which is distributed under the terms specified
* by the Ash General Public License. See the file named LICENSE.
*/
#include <stdio.h>
char *commandname;
void
#ifdef __STDC__
error(char *msg, ...) {
#else
error(msg)
char *msg;
{
#endif
fprintf(stderr, "%s: %s\n", commandname, msg);
exit(2);
}

481
commands/ash/bltin/expr.c Executable file
View file

@ -0,0 +1,481 @@
/*
* The expr and test commands.
*
* Copyright (C) 1989 by Kenneth Almquist. All rights reserved.
* This file is part of ash, which is distributed under the terms specified
* by the Ash General Public License. See the file named LICENSE.
*/
#define main exprcmd
#include "bltin.h"
#include "operators.h"
#include <sys/types.h>
#include <sys/stat.h>
#ifndef S_ISLNK
#define lstat stat
#define S_ISLNK(mode) (0)
#endif
#define STACKSIZE 12
#define NESTINCR 16
/* data types */
#define STRING 0
#define INTEGER 1
#define BOOLEAN 2
/*
* This structure hold a value. The type keyword specifies the type of
* the value, and the union u holds the value. The value of a boolean
* is stored in u.num (1 = TRUE, 0 = FALSE).
*/
struct value {
int type;
union {
char *string;
long num;
} u;
};
struct operator {
short op; /* which operator */
short pri; /* priority of operator */
};
struct filestat {
int op; /* OP_FILE or OP_LFILE */
char *name; /* name of file */
int rcode; /* return code from stat */
struct stat stat; /* status info on file */
};
extern char *match_begin[10]; /* matched string */
extern short match_length[10]; /* defined in regexp.c */
extern short number_parens; /* number of \( \) pairs */
#ifdef __STDC__
int expr_is_false(struct value *);
void expr_operator(int, struct value *, struct filestat *);
int lookup_op(char *, char *const*);
char *re_compile(char *); /* defined in regexp.c */
int re_match(char *, char *); /* defined in regexp.c */
long atol(const char *);
#else
int expr_is_false();
void expr_operator();
int lookup_op();
char *re_compile(); /* defined in regexp.c */
int re_match(); /* defined in regexp.c */
long atol();
#endif
main(argc, argv) char **argv; {
char **ap;
char *opname;
char c;
char *p;
int print;
int nest; /* parenthises nesting */
int op;
int pri;
int skipping;
int binary;
struct operator opstack[STACKSIZE];
struct operator *opsp;
struct value valstack[STACKSIZE + 1];
struct value *valsp;
struct filestat fs;
INITARGS(argv);
c = **argv;
print = 1;
if (c == 't')
print = 0;
else if (c == '[') {
if (! equal(argv[argc - 1], "]"))
error("missing ]");
argv[argc - 1] = NULL;
print = 0;
}
ap = argv + 1;
fs.name = NULL;
/*
* We use operator precedence parsing, evaluating the expression
* as we parse it. Parentheses are handled by bumping up the
* priority of operators using the variable "nest." We use the
* variable "skipping" to turn off evaluation temporarily for the
* short circuit boolean operators. (It is important do the short
* circuit evaluation because under NFS a stat operation can take
* infinitely long.)
*/
nest = 0;
skipping = 0;
opsp = opstack + STACKSIZE;
valsp = valstack;
if (*ap == NULL) {
valstack[0].type = BOOLEAN;
valstack[0].u.num = 0;
goto done;
}
for (;;) {
opname = *ap++;
if (opname == NULL)
syntax: error("syntax error");
if (opname[0] == '(' && opname[1] == '\0') {
nest += NESTINCR;
continue;
} else if (*ap && (op = lookup_op(opname, unary_op)) >= 0) {
if (opsp == &opstack[0])
overflow: error("Expression too complex");
--opsp;
opsp->op = op;
opsp->pri = op_priority[op] + nest;
continue;
} else {
valsp->type = STRING;
valsp->u.string = opname;
valsp++;
}
for (;;) {
opname = *ap++;
if (opname == NULL) {
if (nest != 0)
goto syntax;
pri = 0;
break;
}
if (opname[0] != ')' || opname[1] != '\0') {
if ((op = lookup_op(opname, binary_op)) < 0)
goto syntax;
op += FIRST_BINARY_OP;
pri = op_priority[op] + nest;
break;
}
if ((nest -= NESTINCR) < 0)
goto syntax;
}
while (opsp < &opstack[STACKSIZE] && opsp->pri >= pri) {
binary = opsp->op;
for (;;) {
valsp--;
c = op_argflag[opsp->op];
if (c == OP_INT) {
if (valsp->type == STRING)
valsp->u.num = atol(valsp->u.string);
valsp->type = INTEGER;
} else if (c >= OP_STRING) { /* OP_STRING or OP_FILE */
if (valsp->type == INTEGER) {
p = stalloc(32);
#ifdef SHELL
fmtstr(p, 32, "%d", valsp->u.num);
#else
sprintf(p, "%d", valsp->u.num);
#endif
valsp->u.string = p;
} else if (valsp->type == BOOLEAN) {
if (valsp->u.num)
valsp->u.string = "true";
else
valsp->u.string = "";
}
valsp->type = STRING;
if (c >= OP_FILE
&& (fs.op != c
|| fs.name == NULL
|| ! equal(fs.name, valsp->u.string))) {
fs.op = c;
fs.name = valsp->u.string;
if (c == OP_FILE) {
fs.rcode = stat(valsp->u.string,
&fs.stat);
} else {
fs.rcode = lstat(valsp->u.string,
&fs.stat);
}
}
}
if (binary < FIRST_BINARY_OP)
break;
binary = 0;
}
if (! skipping)
expr_operator(opsp->op, valsp, &fs);
else if (opsp->op == AND1 || opsp->op == OR1)
skipping--;
valsp++; /* push value */
opsp++; /* pop operator */
}
if (opname == NULL)
break;
if (opsp == &opstack[0])
goto overflow;
if (op == AND1 || op == AND2) {
op = AND1;
if (skipping || expr_is_false(valsp - 1))
skipping++;
}
if (op == OR1 || op == OR2) {
op = OR1;
if (skipping || ! expr_is_false(valsp - 1))
skipping++;
}
opsp--;
opsp->op = op;
opsp->pri = pri;
}
done:
if (print) {
if (valstack[0].type == STRING)
printf("%s\n", valstack[0].u.string);
else if (valstack[0].type == INTEGER)
printf("%ld\n", valstack[0].u.num);
else if (valstack[0].u.num != 0)
printf("true\n");
}
return expr_is_false(&valstack[0]);
}
int
expr_is_false(val)
struct value *val;
{
if (val->type == STRING) {
if (val->u.string[0] == '\0')
return 1;
} else { /* INTEGER or BOOLEAN */
if (val->u.num == 0)
return 1;
}
return 0;
}
/*
* Execute an operator. Op is the operator. Sp is the stack pointer;
* sp[0] refers to the first operand, sp[1] refers to the second operand
* (if any), and the result is placed in sp[0]. The operands are converted
* to the type expected by the operator before expr_operator is called.
* Fs is a pointer to a structure which holds the value of the last call
* to stat, to avoid repeated stat calls on the same file.
*/
void
expr_operator(op, sp, fs)
int op;
struct value *sp;
struct filestat *fs;
{
int i;
struct stat st1, st2;
switch (op) {
case NOT:
sp->u.num = expr_is_false(sp);
sp->type = BOOLEAN;
break;
case ISREAD:
i = 04;
goto permission;
case ISWRITE:
i = 02;
goto permission;
case ISEXEC:
i = 01;
permission:
if (fs->stat.st_uid == geteuid())
i <<= 6;
else if (fs->stat.st_gid == getegid())
i <<= 3;
goto filebit; /* true if (stat.st_mode & i) != 0 */
case ISFILE:
i = S_IFREG;
goto filetype;
case ISDIR:
i = S_IFDIR;
goto filetype;
case ISCHAR:
i = S_IFCHR;
goto filetype;
case ISBLOCK:
i = S_IFBLK;
goto filetype;
case ISFIFO:
#ifdef S_IFIFO
i = S_IFIFO;
goto filetype;
#else
goto false;
#endif
filetype:
if ((fs->stat.st_mode & S_IFMT) == i && fs->rcode >= 0) {
true:
sp->u.num = 1;
} else {
false:
sp->u.num = 0;
}
sp->type = BOOLEAN;
break;
case ISSETUID:
i = S_ISUID;
goto filebit;
case ISSETGID:
i = S_ISGID;
goto filebit;
case ISSTICKY:
i = S_ISVTX;
filebit:
if (fs->stat.st_mode & i && fs->rcode >= 0)
goto true;
goto false;
case ISSIZE:
sp->u.num = fs->rcode >= 0? fs->stat.st_size : 0L;
sp->type = INTEGER;
break;
case ISLINK1:
case ISLINK2:
if (S_ISLNK(fs->stat.st_mode) && fs->rcode >= 0)
goto true;
fs->op = OP_FILE; /* not a symlink, so expect a -d or so next */
goto false;
case NEWER:
if (stat(sp->u.string, &st1) != 0) {
sp->u.num = 0;
} else if (stat((sp + 1)->u.string, &st2) != 0) {
sp->u.num = 1;
} else {
sp->u.num = st1.st_mtime >= st2.st_mtime;
}
sp->type = INTEGER;
break;
case ISTTY:
sp->u.num = isatty(sp->u.num);
sp->type = BOOLEAN;
break;
case NULSTR:
if (sp->u.string[0] == '\0')
goto true;
goto false;
case STRLEN:
sp->u.num = strlen(sp->u.string);
sp->type = INTEGER;
break;
case OR1:
case AND1:
/*
* These operators are mostly handled by the parser. If we
* get here it means that both operands were evaluated, so
* the value is the value of the second operand.
*/
*sp = *(sp + 1);
break;
case STREQ:
case STRNE:
i = 0;
if (equal(sp->u.string, (sp + 1)->u.string))
i++;
if (op == STRNE)
i = 1 - i;
sp->u.num = i;
sp->type = BOOLEAN;
break;
case EQ:
if (sp->u.num == (sp + 1)->u.num)
goto true;
goto false;
case NE:
if (sp->u.num != (sp + 1)->u.num)
goto true;
goto false;
case GT:
if (sp->u.num > (sp + 1)->u.num)
goto true;
goto false;
case LT:
if (sp->u.num < (sp + 1)->u.num)
goto true;
goto false;
case LE:
if (sp->u.num <= (sp + 1)->u.num)
goto true;
goto false;
case GE:
if (sp->u.num >= (sp + 1)->u.num)
goto true;
goto false;
case PLUS:
sp->u.num += (sp + 1)->u.num;
break;
case MINUS:
sp->u.num -= (sp + 1)->u.num;
break;
case TIMES:
sp->u.num *= (sp + 1)->u.num;
break;
case DIVIDE:
if ((sp + 1)->u.num == 0)
error("Division by zero");
sp->u.num /= (sp + 1)->u.num;
break;
case REM:
if ((sp + 1)->u.num == 0)
error("Division by zero");
sp->u.num %= (sp + 1)->u.num;
break;
case MATCHPAT:
{
char *pat;
pat = re_compile((sp + 1)->u.string);
if (re_match(pat, sp->u.string)) {
if (number_parens > 0) {
sp->u.string = match_begin[1];
sp->u.string[match_length[1]] = '\0';
} else {
sp->u.num = match_length[0];
sp->type = INTEGER;
}
} else {
if (number_parens > 0) {
sp->u.string[0] = '\0';
} else {
sp->u.num = 0;
sp->type = INTEGER;
}
}
}
break;
}
}
int
lookup_op(name, table)
char *name;
char *const*table;
{
register char *const*tp;
register char const *p;
char c = name[1];
for (tp = table ; (p = *tp) != NULL ; tp++) {
if (p[1] == c && equal(p, name))
return tp - table;
}
return -1;
}

27
commands/ash/bltin/line.c Executable file
View file

@ -0,0 +1,27 @@
/*
* The line command. Reads one line from the standard input and writes it
* to the standard output.
*
* Copyright (C) 1989 by Kenneth Almquist. All rights reserved.
* This file is part of ash, which is distributed under the terms specified
* by the Ash General Public License. See the file named LICENSE.
*/
#define main linecmd
#include "bltin.h"
main(argc, argv) char **argv; {
char c;
for (;;) {
if (read(0, &c, 1) != 1) {
putchar('\n');
return 1;
}
putchar(c);
if (c == '\n')
return 0;
}
}

71
commands/ash/bltin/makefile.not Executable file
View file

@ -0,0 +1,71 @@
# Copyright (C) 1989 by Kenneth Almquist. All rights reserved.
# This file is part of ash, which is distributed under the terms specified
# by the Ash General Public License. See the file named LICENSE.
LIBFILES=catfcmd.o echocmd.o exprcmd.o linecmd.o nlechocmd.o\
operators.o regexp.o
DEBUG=-g
CFLAGS=$(DEBUG)
#CC=gcc
all:$P bltinlib.a catf echo expr line nlecho true umask
bltinlib.a:$P $(LIBFILES)
ar rc $@ $(LIBFILES)
catf: catf.c bltin.h ../shell.h ../error.h error.o stalloc.o
$(CC) $(CFLAGS) -o $@ catf.c error.o stalloc.o
catfcmd.o: catf.c bltin.h ../shell.h ../error.h
$(CC) -DSHELL $(CFLAGS) -c catf.c
mv catf.o $@
expr: expr.c bltin.h ../shell.h operators.h operators.o regexp.o error.o stalloc.o
$(CC) $(CFLAGS) -o $@ expr.c operators.o regexp.o error.o stalloc.o
-rm -f test '['
ln expr test
ln expr '['
exprcmd.o: expr.c bltin.h ../shell.h operators.h
$(CC) -DSHELL $(CFLAGS) -c expr.c
mv expr.o $@
operators.c operators.h: unary_op binary_op mkexpr
./mkexpr
operators.o: ../shell.h operators.h
regexp.o: bltin.h ../shell.h
echo: echo.c bltin.h ../shell.h
$(CC) $(CFLAGS) -o $@ echo.c
echocmd.o: echo.c bltin.h ../shell.h
$(CC) -DSHELL $(CFLAGS) -c echo.c
mv echo.o $@
line: line.c bltin.h ../shell.h
$(CC) $(CFLAGS) -o $@ line.c
linecmd.o: line.c bltin.h ../shell.h
$(CC) -DSHELL $(CFLAGS) -c line.c
mv line.o $@
nlecho: nlecho.c bltin.h ../shell.h
$(CC) $(CFLAGS) -o $@ nlecho.c
nlechocmd.o: nlecho.c bltin.h ../shell.h
$(CC) -DSHELL $(CFLAGS) -c nlecho.c
mv nlecho.o $@
umask: umask.c bltin.h
$(CC) $(CFLAGS) -o $@ umask.c
true:
> :
chmod 755 :
rm -f true
ln : true
stalloc.o: ../shell.h

66
commands/ash/bltin/mkexpr Executable file
View file

@ -0,0 +1,66 @@
# Copyright 1989 by Kenneth Almquist. All rights reserved.
#
# This file is part of ash. Ash is distributed under the terms specified
# by the Ash General Public License. See the file named LICENSE.
# All calls to awk removed, because Minix bawk is deficient. (kjb)
exec > operators.h
i=0
sed -e '/^[^#]/!d' unary_op binary_op | while read line
do
set -$- $line
echo "#define $1 $i"
i=`expr $i + 1`
done
echo
echo "#define FIRST_BINARY_OP" `sed -e '/^[^#]/!d' unary_op | wc -l`
echo '
#define OP_INT 1 /* arguments to operator are integer */
#define OP_STRING 2 /* arguments to operator are string */
#define OP_FILE 3 /* argument is a file name */
#define OP_LFILE 4 /* argument is a file name of a symlink? */
extern char *const unary_op[];
extern char *const binary_op[];
extern const char op_priority[];
extern const char op_argflag[];'
exec > operators.c
echo '/*
* Operators used in the expr/test command.
*/
#include "../shell.h"
#include "operators.h"
char *const unary_op[] = {'
sed -e '/^[^#]/!d
s/[ ][ ]*/ /g
s/^[^ ][^ ]* \([^ ][^ ]*\).*/ "\1",/
' unary_op
echo ' NULL
};
char *const binary_op[] = {'
sed -e '/^[^#]/!d
s/[ ][ ]*/ /g
s/^[^ ][^ ]* \([^ ][^ ]*\).*/ "\1",/
' binary_op
echo ' NULL
};
const char op_priority[] = {'
sed -e '/^[^#]/!d
s/[ ][ ]*/ /g
s/^[^ ][^ ]* [^ ][^ ]* \([^ ][^ ]*\).*/ \1,/
' unary_op binary_op
echo '};
const char op_argflag[] = {'
sed -e '/^[^#]/!d
s/[ ][ ]*/ /g
s/^[^ ][^ ]* [^ ][^ ]* [^ ][^ ]*$/& 0/
s/^[^ ][^ ]* [^ ][^ ]* [^ ][^ ]* \([^ ][^ ]*\)/ \1,/
' unary_op binary_op
echo '};'

25
commands/ash/bltin/nlecho.c Executable file
View file

@ -0,0 +1,25 @@
/*
* Echo the command argument to the standard output, one line at a time.
* This command is useful for debugging th shell and whenever you what
* to output strings literally.
*
* Copyright (C) 1989 by Kenneth Almquist. All rights reserved.
* This file is part of ash, which is distributed under the terms specified
* by the Ash General Public License. See the file named LICENSE.
*/
#define main nlechocmd
#include "bltin.h"
main(argc, argv) char **argv; {
register char **ap;
for (ap = argv + 1 ; *ap ; ap++) {
fputs(*ap, stdout);
putchar('\n');
}
return 0;
}

299
commands/ash/bltin/regexp.c Executable file
View file

@ -0,0 +1,299 @@
/*
* Regular expression matching for expr(1). Bugs: The upper bound of
* a range specified by the \{ feature cannot be zero.
*
* Copyright (C) 1989 by Kenneth Almquist. All rights reserved.
* This file is part of ash, which is distributed under the terms specified
* by the Ash General Public License. See the file named LICENSE.
*/
#include "bltin.h"
#define RE_END 0 /* end of regular expression */
#define RE_LITERAL 1 /* normal character follows */
#define RE_DOT 2 /* "." */
#define RE_CCL 3 /* "[...]" */
#define RE_NCCL 4 /* "[^...]" */
#define RE_LP 5 /* "\(" */
#define RE_RP 6 /* "\)" */
#define RE_MATCHED 7 /* "\digit" */
#define RE_EOS 8 /* "$" matches end of string */
#define RE_STAR 9 /* "*" */
#define RE_RANGE 10 /* "\{num,num\}" */
char *match_begin[10];
short match_length[10];
short number_parens;
static int match();
char *
re_compile(pattern)
char *pattern;
{
register char *p;
register char c;
char *comp;
register char *q;
char *begin;
char *endp;
register int len;
int first;
int type;
char *stackp;
char stack[10];
int paren_num;
int i;
char *malloc();
p = pattern;
if (*p == '^')
p++;
comp = q = malloc(2 * strlen(p) + 1);
begin = q;
stackp = stack;
paren_num = 0;
for (;;) {
switch (c = *p++) {
case '\0':
*q = '\0';
goto out;
case '.':
*q++ = RE_DOT;
len = 1;
break;
case '[':
begin = q;
*q = RE_CCL;
if (*p == '^') {
*q = RE_NCCL;
p++;
}
q++;
first = 1;
while (*p != ']' || first == 1) {
if (p[1] == '-' && p[2] != ']') {
*q++ = '-';
*q++ = p[0];
*q++ = p[2];
p += 3;
} else if (*p == '-') {
*q++ = '-';
*q++ = '-';
*q++ = '-';
p++;
} else {
*q++ = *p++;
}
first = 0;
}
p++;
*q++ = '\0';
len = q - begin;
break;
case '$':
if (*p != '\0')
goto dft;
*q++ = RE_EOS;
break;
case '*':
if (len == 0)
goto dft;
type = RE_STAR;
range:
i = (type == RE_RANGE)? 3 : 1;
endp = q + i;
begin = q - len;
do {
--q;
*(q + i) = *q;
} while (--len > 0);
q = begin;
*q++ = type;
if (type == RE_RANGE) {
i = 0;
while ((unsigned)(*p - '0') <= 9)
i = 10 * i + (*p++ - '0');
*q++ = i;
if (*p != ',') {
*q++ = i;
} else {
p++;
i = 0;
while ((unsigned)(*p - '0') <= 9)
i = 10 * i + (*p++ - '0');
*q++ = i;
}
if (*p != '\\' || *++p != '}')
error("RE error");
p++;
}
q = endp;
break;
case '\\':
if ((c = *p++) == '(') {
if (++paren_num > 9)
error("RE error");
*q++ = RE_LP;
*q++ = paren_num;
*stackp++ = paren_num;
len = 0;
} else if (c == ')') {
if (stackp == stack)
error("RE error");
*q++ = RE_RP;
*q++ = *--stackp;
len = 0;
} else if (c == '{') {
type = RE_RANGE;
goto range;
} else if ((unsigned)(c - '1') < 9) {
/* should check validity here */
*q++ = RE_MATCHED;
*q++ = c - '0';
len = 2;
} else {
goto dft;
}
break;
default:
dft: *q++ = RE_LITERAL;
*q++ = c;
len = 2;
break;
}
}
out:
if (stackp != stack)
error("RE error");
number_parens = paren_num;
return comp;
}
re_match(pattern, string)
char *pattern;
char *string;
{
char **pp;
match_begin[0] = string;
for (pp = &match_begin[1] ; pp <= &match_begin[9] ; pp++)
*pp = 0;
return match(pattern, string);
}
static
match(pattern, string)
char *pattern;
char *string;
{
register char *p, *q;
int counting;
int low, high, count;
char *curpat;
char *start_count;
int negate;
int found;
char *r;
int len;
char c;
p = pattern;
q = string;
counting = 0;
for (;;) {
if (counting) {
if (++count > high)
goto bad;
p = curpat;
}
switch (*p++) {
case RE_END:
match_length[0] = q - match_begin[0];
return 1;
case RE_LITERAL:
if (*q++ != *p++)
goto bad;
break;
case RE_DOT:
if (*q++ == '\0')
goto bad;
break;
case RE_CCL:
negate = 0;
goto ccl;
case RE_NCCL:
negate = 1;
ccl:
found = 0;
c = *q++;
while (*p) {
if (*p == '-') {
if (c >= *++p && c <= *++p)
found = 1;
} else {
if (c == *p)
found = 1;
}
p++;
}
p++;
if (found == negate)
goto bad;
break;
case RE_LP:
match_begin[*p++] = q;
break;
case RE_RP:
match_length[*p] = q - match_begin[*p];
p++;
break;
case RE_MATCHED:
r = match_begin[*p];
len = match_length[*p++];
while (--len >= 0) {
if (*q++ != *r++)
goto bad;
}
break;
case RE_EOS:
if (*q != '\0')
goto bad;
break;
case RE_STAR:
low = 0;
high = 32767;
goto range;
case RE_RANGE:
low = *p++;
high = *p++;
if (high == 0)
high = 32767;
range:
curpat = p;
start_count = q;
count = 0;
counting++;
break;
}
}
bad:
if (! counting)
return 0;
len = 1;
if (*curpat == RE_MATCHED)
len = match_length[curpat[1]];
while (--count >= low) {
if (match(p, start_count + count * len))
return 1;
}
return 0;
}

21
commands/ash/bltin/stalloc.c Executable file
View file

@ -0,0 +1,21 @@
/*
* Copyright (C) 1989 by Kenneth Almquist. All rights reserved.
* This file is part of ash, which is distributed under the terms specified
* by the Ash General Public License. See the file named LICENSE.
*/
#include "../shell.h"
void error();
pointer malloc();
pointer
stalloc(nbytes) {
register pointer p;
if ((p = malloc(nbytes)) == NULL)
error("Out of space");
return p;
}

19
commands/ash/bltin/umask.c Executable file
View file

@ -0,0 +1,19 @@
/*
* Copyright (C) 1989 by Kenneth Almquist. All rights reserved.
* This file is part of ash, which is distributed under the terms specified
* by the Ash General Public License. See the file named LICENSE.
*/
#include <stdio.h>
main(argc, argv) char **argv; {
int mask;
if (argc > 1) {
fprintf(stderr, "umask: only builtin version of umask can set value\n");
exit(2);
}
printf("%.4o\n", umask(0));
return 0;
}

24
commands/ash/bltin/unary_op Executable file
View file

@ -0,0 +1,24 @@
# List of unary operators used by test/expr.
#
# Copyright (C) 1989 by Kenneth Almquist. All rights reserved.
# This file is part of ash, which is distributed under the terms specified
# by the Ash General Public License. See the file named LICENSE.
NOT ! 3
ISREAD -r 12 OP_FILE
ISWRITE -w 12 OP_FILE
ISEXEC -x 12 OP_FILE
ISFILE -f 12 OP_FILE
ISDIR -d 12 OP_FILE
ISCHAR -c 12 OP_FILE
ISBLOCK -b 12 OP_FILE
ISFIFO -p 12 OP_FILE
ISSETUID -u 12 OP_FILE
ISSETGID -g 12 OP_FILE
ISSTICKY -k 12 OP_FILE
ISSIZE -s 12 OP_FILE
ISLINK1 -h 12 OP_LFILE
ISLINK2 -L 12 OP_LFILE
ISTTY -t 12 OP_INT
NULSTR -z 12 OP_STRING
STRLEN -n 12 OP_STRING

83
commands/ash/builtins.table Executable file
View file

@ -0,0 +1,83 @@
#!/bin/sh -
#
# Copyright (c) 1991 The Regents of the University of California.
# All rights reserved.
#
# This code is derived from software contributed to Berkeley by
# Kenneth Almquist.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. All advertising materials mentioning features or use of this software
# must display the following acknowledgement:
# This product includes software developed by the University of
# California, Berkeley and its contributors.
# 4. Neither the name of the University nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# @(#)builtins 5.1 (Berkeley) 3/7/91
#
# This file lists all the builtin commands. The first column is the name
# of a C routine. The -j flag, if present, specifies that this command
# is to be excluded from systems without job control. The rest of the line
# specifies the command name or names used to run the command. The entry
# for nullcmd, which is run when the user does not specify a command, must
# come first.
#
# Copyright (C) 1989 by Kenneth Almquist. All rights reserved.
# This file is part of ash, which is distributed under the terms specified
# by the Ash General Public License. See the file named LICENSE.
bltincmd command
#alloccmd alloc
bgcmd -j bg
breakcmd break continue
#catfcmd catf
cdcmd cd chdir
dotcmd .
echocmd echo
evalcmd eval
execcmd exec
exitcmd exit
exportcmd export readonly
exprcmd expr test [
fgcmd -j fg
getoptscmd getopts
hashcmd hash
jobidcmd jobid
jobscmd jobs
#lccmd lc
#linecmd line
localcmd local
#nlechocmd nlecho
pwdcmd pwd
readcmd read
returncmd return
setcmd set
setvarcmd setvar
shiftcmd shift
trapcmd trap
truecmd : true false
umaskcmd umask
unsetcmd unset
waitcmd wait

372
commands/ash/cd.c Executable file
View file

@ -0,0 +1,372 @@
/*-
* Copyright (c) 1991 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Kenneth Almquist.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char sccsid[] = "@(#)cd.c 5.2 (Berkeley) 3/13/91";
#endif /* not lint */
/*
* The cd and pwd commands.
*/
#include "shell.h"
#include "var.h"
#include "nodes.h" /* for jobs.h */
#include "jobs.h"
#include "options.h"
#include "output.h"
#include "memalloc.h"
#include "error.h"
#include "mystring.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#ifdef __STDC__
STATIC int docd(char *, int, int);
STATIC void updatepwd(char *);
STATIC void getpwd(void);
STATIC char *getcomponent(void);
#else
STATIC int docd();
STATIC void updatepwd();
STATIC void getpwd();
STATIC char *getcomponent();
#endif
char *curdir; /* current working directory */
STATIC char *cdcomppath;
#if UDIR || TILDE
extern int didudir; /* set if /u/logname or ~logname expanded */
#endif
int
cdcmd(argc, argv) char **argv; {
char *dest;
char *path;
char *p;
struct stat statb;
char *padvance();
int tohome= 0;
nextopt(nullstr);
if ((dest = *argptr) == NULL) {
if ((dest = bltinlookup("HOME", 1)) == NULL)
error("HOME not set");
tohome = 1;
}
if (*dest == '/' || (path = bltinlookup("CDPATH", 1)) == NULL)
path = nullstr;
while ((p = padvance(&path, dest)) != NULL) {
if (stat(p, &statb) >= 0
&& (statb.st_mode & S_IFMT) == S_IFDIR
&& docd(p, strcmp(p, dest), tohome) >= 0)
return 0;
}
error("can't cd to %s", dest);
}
/*
* Actually do the chdir. If the name refers to symbolic links, we
* compute the actual directory name before doing the cd. In an
* interactive shell, print the directory name if "print" is nonzero
* or if the name refers to a symbolic link. We also print the name
* if "/u/logname" was expanded in it, since this is similar to a
* symbolic link. (The check for this breaks if the user gives the
* cd command some additional, unused arguments.)
*/
#if SYMLINKS == 0
STATIC int
docd(dest, print, tohome)
char *dest;
{
#if UDIR || TILDE
if (didudir)
print = 1;
#endif
INTOFF;
if (chdir(dest) < 0) {
INTON;
return -1;
}
updatepwd(dest);
INTON;
if (print && iflag)
out1fmt("%s\n", stackblock());
return 0;
}
#else
STATIC int
docd(dest, print, tohome)
char *dest;
{
register char *p;
register char *q;
char *symlink;
char *component;
struct stat statb;
int first;
int i;
TRACE(("docd(\"%s\", %d, %d) called\n", dest, print, tohome));
#if UDIR || TILDE
if (didudir)
print = 1;
#endif
top:
cdcomppath = dest;
STARTSTACKSTR(p);
if (*dest == '/') {
STPUTC('/', p);
cdcomppath++;
}
first = 1;
while ((q = getcomponent()) != NULL) {
if (q[0] == '\0' || q[0] == '.' && q[1] == '\0')
continue;
if (! first)
STPUTC('/', p);
first = 0;
component = q;
while (*q)
STPUTC(*q++, p);
if (equal(component, ".."))
continue;
STACKSTRNUL(p);
if (lstat(stackblock(), &statb) < 0)
error("lstat %s failed", stackblock());
if ((statb.st_mode & S_IFMT) != S_IFLNK)
continue;
/* Hit a symbolic link. We have to start all over again. */
print = 1;
STPUTC('\0', p);
symlink = grabstackstr(p);
i = (int)statb.st_size + 2; /* 2 for '/' and '\0' */
if (cdcomppath != NULL)
i += strlen(cdcomppath);
p = stalloc(i);
if (readlink(symlink, p, (int)statb.st_size) < 0) {
error("readlink %s failed", stackblock());
}
if (cdcomppath != NULL) {
p[(int)statb.st_size] = '/';
scopy(cdcomppath, p + (int)statb.st_size + 1);
} else {
p[(int)statb.st_size] = '\0';
}
if (p[0] != '/') { /* relative path name */
char *r;
q = r = symlink;
while (*q) {
if (*q++ == '/')
r = q;
}
*r = '\0';
dest = stalloc(strlen(symlink) + strlen(p) + 1);
scopy(symlink, dest);
strcat(dest, p);
} else {
dest = p;
}
goto top;
}
STPUTC('\0', p);
p = grabstackstr(p);
INTOFF;
/* The empty string is not a legal argument to chdir on a POSIX 1003.1
* system. */
if (p[0] != '\0' && chdir(p) < 0) {
INTON;
return -1;
}
updatepwd(p);
INTON;
if (print && !tohome && iflag)
out1fmt("%s\n", p);
return 0;
}
#endif /* SYMLINKS */
/*
* Get the next component of the path name pointed to by cdcomppath.
* This routine overwrites the string pointed to by cdcomppath.
*/
STATIC char *
getcomponent() {
register char *p;
char *start;
if ((p = cdcomppath) == NULL)
return NULL;
start = cdcomppath;
while (*p != '/' && *p != '\0')
p++;
if (*p == '\0') {
cdcomppath = NULL;
} else {
*p++ = '\0';
cdcomppath = p;
}
return start;
}
/*
* Update curdir (the name of the current directory) in response to a
* cd command. We also call hashcd to let the routines in exec.c know
* that the current directory has changed.
*/
void hashcd();
STATIC void
updatepwd(dir)
char *dir;
{
char *new;
char *p;
hashcd(); /* update command hash table */
cdcomppath = stalloc(strlen(dir) + 1);
scopy(dir, cdcomppath);
STARTSTACKSTR(new);
if (*dir != '/') {
if (curdir == NULL)
return;
p = curdir;
while (*p)
STPUTC(*p++, new);
if (p[-1] == '/')
STUNPUTC(new);
}
while ((p = getcomponent()) != NULL) {
if (equal(p, "..")) {
while (new > stackblock() && (STUNPUTC(new), *new) != '/');
} else if (*p != '\0' && ! equal(p, ".")) {
STPUTC('/', new);
while (*p)
STPUTC(*p++, new);
}
}
if (new == stackblock())
STPUTC('/', new);
STACKSTRNUL(new);
if (curdir)
ckfree(curdir);
curdir = savestr(stackblock());
}
int
pwdcmd(argc, argv) char **argv; {
getpwd();
out1str(curdir);
out1c('\n');
return 0;
}
/*
* Run /bin/pwd to find out what the current directory is. We suppress
* interrupts throughout most of this, but the user can still break out
* of it by killing the pwd program. If we already know the current
* directory, this routine returns immediately.
*/
#define MAXPWD 256
STATIC void
getpwd() {
char buf[MAXPWD];
char *p;
int i;
int status;
struct job *jp;
int pip[2];
if (curdir)
return;
INTOFF;
if (pipe(pip) < 0)
error("Pipe call failed");
jp = makejob((union node *)NULL, 1);
if (forkshell(jp, (union node *)NULL, FORK_NOJOB) == 0) {
close(pip[0]);
if (pip[1] != 1) {
close(1);
copyfd(pip[1], 1);
close(pip[1]);
}
execl("/bin/pwd", "pwd", (char *)0);
error("Cannot exec /bin/pwd");
}
close(pip[1]);
pip[1] = -1;
p = buf;
while ((i = read(pip[0], p, buf + MAXPWD - p)) > 0
|| i == -1 && errno == EINTR) {
if (i > 0)
p += i;
}
close(pip[0]);
pip[0] = -1;
status = waitforjob(jp);
if (status != 0)
error((char *)0);
if (i < 0 || p == buf || p[-1] != '\n')
error("pwd command failed");
p[-1] = '\0';
curdir = savestr(buf);
INTON;
}

194
commands/ash/dirent.c Executable file
View file

@ -0,0 +1,194 @@
/*-
* Copyright (c) 1991 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Kenneth Almquist.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char sccsid[] = "@(#)dirent.c 5.1 (Berkeley) 3/7/91";
#endif /* not lint */
#include "shell.h" /* definitions for pointer, NULL, DIRENT, and BSD */
#if ! DIRENT
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#ifndef S_ISDIR /* macro to test for directory file */
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
#endif
#ifdef BSD
#ifdef __STDC__
int stat(char *, struct stat *);
#else
int stat();
#endif
/*
* The BSD opendir routine doesn't check that what is being opened is a
* directory, so we have to include the check in a wrapper routine.
*/
#undef opendir
DIR *
myopendir(dirname)
char *dirname; /* name of directory */
{
struct stat statb;
if (stat(dirname, &statb) != 0 || ! S_ISDIR(statb.st_mode)) {
errno = ENOTDIR;
return NULL; /* not a directory */
}
return opendir(dirname);
}
#else /* not BSD */
/*
* Dirent routines for old style file systems.
*/
#ifdef __STDC__
pointer malloc(unsigned);
void free(pointer);
int open(char *, int, ...);
int close(int);
int fstat(int, struct stat *);
#else
pointer malloc();
void free();
int open();
int close();
int fstat();
#endif
DIR *
opendir(dirname)
char *dirname; /* name of directory */
{
register DIR *dirp; /* -> malloc'ed storage */
register int fd; /* file descriptor for read */
struct stat statb; /* result of fstat() */
#ifdef O_NDELAY
fd = open(dirname, O_RDONLY|O_NDELAY);
#else
fd = open(dirname, O_RDONLY);
#endif
if (fd < 0)
return NULL; /* errno set by open() */
if (fstat(fd, &statb) != 0 || !S_ISDIR(statb.st_mode)) {
(void)close(fd);
errno = ENOTDIR;
return NULL; /* not a directory */
}
if ((dirp = (DIR *)malloc(sizeof(DIR))) == NULL) {
(void)close(fd);
errno = ENOMEM;
return NULL; /* not enough memory */
}
dirp->dd_fd = fd;
dirp->dd_nleft = 0; /* refill needed */
return dirp;
}
int
closedir(dirp)
register DIR *dirp; /* stream from opendir() */
{
register int fd;
if (dirp == NULL) {
errno = EFAULT;
return -1; /* invalid pointer */
}
fd = dirp->dd_fd;
free((pointer)dirp);
return close(fd);
}
struct dirent *
readdir(dirp)
register DIR *dirp; /* stream from opendir() */
{
register struct direct *dp;
register char *p, *q;
register int i;
do {
if ((dirp->dd_nleft -= sizeof (struct direct)) < 0) {
if ((i = read(dirp->dd_fd,
(char *)dirp->dd_buf,
DIRBUFENT*sizeof(struct direct))) <= 0) {
if (i == 0)
errno = 0; /* unnecessary */
return NULL; /* EOF or error */
}
dirp->dd_loc = dirp->dd_buf;
dirp->dd_nleft = i - sizeof (struct direct);
}
dp = dirp->dd_loc++;
} while (dp->d_ino == 0);
dirp->dd_entry.d_ino = dp->d_ino;
/* now copy the name, nul terminating it */
p = dp->d_name;
q = dirp->dd_entry.d_name;
i = DIRSIZ;
while (--i >= 0 && *p != '\0')
*q++ = *p++;
*q = '\0';
return &dirp->dd_entry;
}
#endif /* BSD */
#endif /* DIRENT */

252
commands/ash/error.c Executable file
View file

@ -0,0 +1,252 @@
/*-
* Copyright (c) 1991 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Kenneth Almquist.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char sccsid[] = "@(#)error.c 5.1 (Berkeley) 3/7/91";
#endif /* not lint */
/*
* Errors and exceptions.
*/
#include "shell.h"
#include "main.h"
#include "options.h"
#include "output.h"
#include "error.h"
#include <sys/types.h>
#include <signal.h>
#ifdef __STDC__
#include "stdarg.h"
#else
#include <varargs.h>
#endif
#include <errno.h>
/*
* Code to handle exceptions in C.
*/
struct jmploc *handler;
int exception;
volatile int suppressint;
volatile int intpending;
char *commandname;
/*
* Called to raise an exception. Since C doesn't include exceptions, we
* just do a longjmp to the exception handler. The type of exception is
* stored in the global variable "exception".
*/
void
exraise(e) {
if (handler == NULL)
abort();
exception = e;
longjmp(handler->loc, 1);
}
/*
* Called from trap.c when a SIGINT is received. (If the user specifies
* that SIGINT is to be trapped or ignored using the trap builtin, then
* this routine is not called.) Suppressint is nonzero when interrupts
* are held using the INTOFF macro. The call to _exit is necessary because
* there is a short period after a fork before the signal handlers are
* set to the appropriate value for the child. (The test for iflag is
* just defensive programming.)
*/
void
onint() {
if (suppressint) {
intpending++;
return;
}
intpending = 0;
#ifdef BSD
sigsetmask(0);
#endif
if (rootshell && iflag)
exraise(EXINT);
else
_exit(128 + SIGINT);
}
void
error2(a, b)
char *a, *b;
{
error("%s: %s", a, b);
}
/*
* Error is called to raise the error exception. If the first argument
* is not NULL then error prints an error message using printf style
* formatting. It then raises the error exception.
*/
#ifdef __STDC__
void
error(char *msg, ...) {
#else
void
error(va_alist)
va_dcl
{
char *msg;
#endif
va_list ap;
CLEAR_PENDING_INT;
INTOFF;
#ifdef __STDC__
va_start(ap, msg);
#else
va_start(ap);
msg = va_arg(ap, char *);
#endif
#if DEBUG
if (msg)
TRACE(("error(\"%s\") pid=%d\n", msg, getpid()));
else
TRACE(("error(NULL) pid=%d\n", getpid()));
#endif
if (msg) {
if (commandname)
outfmt(&errout, "%s: ", commandname);
doformat(&errout, msg, ap);
out2c('\n');
}
va_end(ap);
flushall();
exraise(EXERROR);
}
#ifdef notdef /* These strange error messages only confuse. -- kjb */
/*
* Table of error messages.
*/
struct errname {
short errcode; /* error number */
short action; /* operation which encountered the error */
char *msg; /* text describing the error */
};
#define ALL (E_OPEN|E_CREAT|E_EXEC)
STATIC const struct errname errormsg[] = {
EINTR, ALL, "interrupted",
EACCES, ALL, "permission denied",
EIO, ALL, "I/O error",
ENOENT, E_OPEN, "no such file",
ENOENT, E_CREAT, "directory nonexistent",
ENOENT, E_EXEC, "not found",
ENOTDIR, E_OPEN, "no such file",
ENOTDIR, E_CREAT, "directory nonexistent",
ENOTDIR, E_EXEC, "not found",
ENOEXEC, ALL, "not an executable",
EISDIR, ALL, "is a directory",
/* EMFILE, ALL, "too many open files", */
ENFILE, ALL, "file table overflow",
ENOSPC, ALL, "file system full",
#ifdef EDQUOT
EDQUOT, ALL, "disk quota exceeded",
#endif
#ifdef ENOSR
ENOSR, ALL, "no streams resources",
#endif
ENXIO, ALL, "no such device or address",
EROFS, ALL, "read-only file system",
ETXTBSY, ALL, "text busy",
#ifdef SYSV
EAGAIN, E_EXEC, "not enough memory",
#endif
ENOMEM, ALL, "not enough memory",
#ifdef ENOLINK
ENOLINK, ALL, "remote access failed",
#endif
#ifdef EMULTIHOP
EMULTIHOP, ALL, "remote access failed",
#endif
#ifdef ECOMM
ECOMM, ALL, "remote access failed",
#endif
#ifdef ESTALE
ESTALE, ALL, "remote access failed",
#endif
#ifdef ETIMEDOUT
ETIMEDOUT, ALL, "remote access failed",
#endif
#ifdef ELOOP
ELOOP, ALL, "symbolic link loop",
#endif
E2BIG, E_EXEC, "argument list too long",
#ifdef ELIBACC
ELIBACC, E_EXEC, "shared library missing",
#endif
0, 0, NULL
};
/*
* Return a string describing an error. The returned string may be a
* pointer to a static buffer that will be overwritten on the next call.
* Action describes the operation that got the error.
*/
char *
errmsg(e, action) {
const struct errname *ep;
static char buf[12];
for (ep = errormsg ; ep->errcode ; ep++) {
if (ep->errcode == e && (ep->action & action) != 0)
return ep->msg;
}
fmtstr(buf, sizeof buf, "error %d", e);
return buf;
}
#endif

116
commands/ash/error.h Executable file
View file

@ -0,0 +1,116 @@
/*-
* Copyright (c) 1991 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Kenneth Almquist.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)error.h 5.1 (Berkeley) 3/7/91
*/
/*
* Types of operations (passed to the errmsg routine).
*/
#define E_OPEN 01 /* opening a file */
#define E_CREAT 02 /* creating a file */
#define E_EXEC 04 /* executing a program */
/*
* We enclose jmp_buf in a structure so that we can declare pointers to
* jump locations. The global variable handler contains the location to
* jump to when an exception occurs, and the global variable exception
* contains a code identifying the exeception. To implement nested
* exception handlers, the user should save the value of handler on entry
* to an inner scope, set handler to point to a jmploc structure for the
* inner scope, and restore handler on exit from the scope.
*/
#include <setjmp.h>
struct jmploc {
jmp_buf loc;
};
extern struct jmploc *handler;
extern int exception;
/* exceptions */
#define EXINT 0 /* SIGINT received */
#define EXERROR 1 /* a generic error */
#define EXSHELLPROC 2 /* execute a shell procedure */
/*
* These macros allow the user to suspend the handling of interrupt signals
* over a period of time. This is similar to SIGHOLD to or sigblock, but
* much more efficient and portable. (But hacking the kernel is so much
* more fun than worrying about efficiency and portability. :-))
*/
extern volatile int suppressint;
extern volatile int intpending;
extern char *commandname; /* name of command--printed on error */
#define INTOFF suppressint++
#define INTON if (--suppressint == 0 && intpending) onint(); else
#define FORCEINTON {suppressint = 0; if (intpending) onint();}
#define CLEAR_PENDING_INT intpending = 0
#define int_pending() intpending
#ifdef __STDC__
void exraise(int);
void onint(void);
void error2(char *, char *);
void error(char *, ...);
char *errmsg(int, int);
#else
void exraise();
void onint();
void error2();
void error();
char *errmsg();
#endif
/* Errmsg uses confusingly different messages. Prefer strerror(). -- kjb */
#define errmsg(errno, action) strerror(errno)
/*
* BSD setjmp saves the signal mask, which violates ANSI C and takes time,
* so we use _setjmp instead.
*/
#ifdef BSD
#define setjmp(jmploc) _setjmp(jmploc)
#define longjmp(jmploc, val) _longjmp(jmploc, val)
#endif

926
commands/ash/eval.c Executable file
View file

@ -0,0 +1,926 @@
/*-
* Copyright (c) 1991 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Kenneth Almquist.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char sccsid[] = "@(#)eval.c 5.3 (Berkeley) 4/12/91";
#endif /* not lint */
/*
* Evaluate a command.
*/
#include "shell.h"
#include "nodes.h"
#include "syntax.h"
#include "expand.h"
#include "parser.h"
#include "jobs.h"
#include "eval.h"
#include "builtins.h"
#include "options.h"
#include "exec.h"
#include "redir.h"
#include "input.h"
#include "output.h"
#include "trap.h"
#include "var.h"
#include "memalloc.h"
#include "error.h"
#include "mystring.h"
#include <sys/types.h>
#include <signal.h>
/* flags in argument to evaltree */
#define EV_EXIT 01 /* exit after evaluating tree */
#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
#define EV_BACKCMD 04 /* command executing within back quotes */
/* reasons for skipping commands (see comment on breakcmd routine) */
#define SKIPBREAK 1
#define SKIPCONT 2
#define SKIPFUNC 3
MKINIT int evalskip; /* set if we are skipping commands */
STATIC int skipcount; /* number of levels to skip */
MKINIT int loopnest; /* current loop nesting level */
int funcnest; /* depth of function calls */
char *commandname;
struct strlist *cmdenviron;
int exitstatus; /* exit status of last command */
#ifdef __STDC__
STATIC void evalloop(union node *);
STATIC void evalfor(union node *);
STATIC void evalcase(union node *, int);
STATIC void evalsubshell(union node *, int);
STATIC void expredir(union node *);
STATIC void evalpipe(union node *);
STATIC void evalcommand(union node *, int, struct backcmd *);
STATIC void prehash(union node *);
#else
STATIC void evalloop();
STATIC void evalfor();
STATIC void evalcase();
STATIC void evalsubshell();
STATIC void expredir();
STATIC void evalpipe();
STATIC void evalcommand();
STATIC void prehash();
#endif
/*
* Called to reset things after an exception.
*/
#ifdef mkinit
INCLUDE "eval.h"
RESET {
evalskip = 0;
loopnest = 0;
funcnest = 0;
}
SHELLPROC {
exitstatus = 0;
}
#endif
/*
* The eval commmand.
*/
evalcmd(argc, argv)
char **argv;
{
char *p;
char *concat;
char **ap;
if (argc > 1) {
p = argv[1];
if (argc > 2) {
STARTSTACKSTR(concat);
ap = argv + 2;
for (;;) {
while (*p)
STPUTC(*p++, concat);
if ((p = *ap++) == NULL)
break;
STPUTC(' ', concat);
}
STPUTC('\0', concat);
p = grabstackstr(concat);
}
evalstring(p);
}
return exitstatus;
}
/*
* Execute a command or commands contained in a string.
*/
void
evalstring(s)
char *s;
{
union node *n;
struct stackmark smark;
setstackmark(&smark);
setinputstring(s, 1);
while ((n = parsecmd(0)) != NEOF) {
evaltree(n, 0);
popstackmark(&smark);
}
popfile();
popstackmark(&smark);
}
/*
* Evaluate a parse tree. The value is left in the global variable
* exitstatus.
*/
void
evaltree(n, flags)
union node *n;
{
if (n == NULL) {
TRACE(("evaltree(NULL) called\n"));
return;
}
TRACE(("evaltree(0x%x: %d) called\n", (int)n, n->type));
switch (n->type) {
case NSEMI:
evaltree(n->nbinary.ch1, 0);
if (evalskip)
goto out;
evaltree(n->nbinary.ch2, flags);
break;
case NAND:
evaltree(n->nbinary.ch1, EV_TESTED);
if (evalskip || exitstatus != 0)
goto out;
evaltree(n->nbinary.ch2, flags);
break;
case NOR:
evaltree(n->nbinary.ch1, EV_TESTED);
if (evalskip || exitstatus == 0)
goto out;
evaltree(n->nbinary.ch2, flags);
break;
case NREDIR:
expredir(n->nredir.redirect);
redirect(n->nredir.redirect, REDIR_PUSH);
evaltree(n->nredir.n, flags);
popredir();
break;
case NSUBSHELL:
evalsubshell(n, flags);
break;
case NBACKGND:
evalsubshell(n, flags);
break;
case NIF: {
int status = 0;
evaltree(n->nif.test, EV_TESTED);
if (evalskip)
goto out;
if (exitstatus == 0) {
evaltree(n->nif.ifpart, flags);
status = exitstatus;
} else if (n->nif.elsepart) {
evaltree(n->nif.elsepart, flags);
status = exitstatus;
}
exitstatus = status;
break;
}
case NWHILE:
case NUNTIL:
evalloop(n);
break;
case NFOR:
evalfor(n);
break;
case NCASE:
evalcase(n, flags);
break;
case NDEFUN:
defun(n->narg.text, n->narg.next);
exitstatus = 0;
break;
case NPIPE:
evalpipe(n);
break;
case NCMD:
evalcommand(n, flags, (struct backcmd *)NULL);
break;
default:
out1fmt("Node type = %d\n", n->type);
flushout(&output);
break;
}
out:
if (pendingsigs)
dotrap();
if ((flags & EV_EXIT) || (eflag == 1 && exitstatus && !(flags & EV_TESTED)))
exitshell(exitstatus);
}
STATIC void
evalloop(n)
union node *n;
{
int status;
loopnest++;
status = 0;
for (;;) {
evaltree(n->nbinary.ch1, EV_TESTED);
if (evalskip) {
skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
evalskip = 0;
continue;
}
if (evalskip == SKIPBREAK && --skipcount <= 0)
evalskip = 0;
break;
}
if (n->type == NWHILE) {
if (exitstatus != 0)
break;
} else {
if (exitstatus == 0)
break;
}
evaltree(n->nbinary.ch2, 0);
status = exitstatus;
if (evalskip)
goto skipping;
}
loopnest--;
exitstatus = status;
}
STATIC void
evalfor(n)
union node *n;
{
struct arglist arglist;
union node *argp;
struct strlist *sp;
struct stackmark smark;
setstackmark(&smark);
arglist.lastp = &arglist.list;
for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
expandarg(argp, &arglist, 1);
if (evalskip)
goto out;
}
*arglist.lastp = NULL;
exitstatus = 0;
loopnest++;
for (sp = arglist.list ; sp ; sp = sp->next) {
setvar(n->nfor.var, sp->text, 0);
evaltree(n->nfor.body, 0);
if (evalskip) {
if (evalskip == SKIPCONT && --skipcount <= 0) {
evalskip = 0;
continue;
}
if (evalskip == SKIPBREAK && --skipcount <= 0)
evalskip = 0;
break;
}
}
loopnest--;
out:
popstackmark(&smark);
}
STATIC void
evalcase(n, flags)
union node *n;
{
union node *cp;
union node *patp;
struct arglist arglist;
struct stackmark smark;
setstackmark(&smark);
arglist.lastp = &arglist.list;
expandarg(n->ncase.expr, &arglist, 0);
for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
if (casematch(patp, arglist.list->text)) {
if (evalskip == 0) {
evaltree(cp->nclist.body, flags);
}
goto out;
}
}
}
out:
popstackmark(&smark);
}
/*
* Kick off a subshell to evaluate a tree.
*/
STATIC void
evalsubshell(n, flags)
union node *n;
{
struct job *jp;
int backgnd = (n->type == NBACKGND);
expredir(n->nredir.redirect);
jp = makejob(n, 1);
if (forkshell(jp, n, backgnd) == 0) {
if (backgnd)
flags &=~ EV_TESTED;
redirect(n->nredir.redirect, 0);
evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
}
if (! backgnd) {
INTOFF;
exitstatus = waitforjob(jp);
INTON;
}
}
/*
* Compute the names of the files in a redirection list.
*/
STATIC void
expredir(n)
union node *n;
{
register union node *redir;
for (redir = n ; redir ; redir = redir->nfile.next) {
if (redir->type == NFROM
|| redir->type == NTO
|| redir->type == NAPPEND) {
struct arglist fn;
fn.lastp = &fn.list;
expandarg(redir->nfile.fname, &fn, 0);
redir->nfile.expfname = fn.list->text;
}
}
}
/*
* Evaluate a pipeline. All the processes in the pipeline are children
* of the process creating the pipeline. (This differs from some versions
* of the shell, which make the last process in a pipeline the parent
* of all the rest.)
*/
STATIC void
evalpipe(n)
union node *n;
{
struct job *jp;
struct nodelist *lp;
int pipelen;
int prevfd;
int pip[2];
TRACE(("evalpipe(0x%x) called\n", (int)n));
pipelen = 0;
for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
pipelen++;
INTOFF;
jp = makejob(n, pipelen);
prevfd = -1;
for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
prehash(lp->n);
pip[1] = -1;
if (lp->next) {
if (pipe(pip) < 0) {
close(prevfd);
error("Pipe call failed");
}
}
if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
INTON;
if (prevfd > 0) {
close(0);
copyfd(prevfd, 0);
close(prevfd);
}
if (pip[1] >= 0) {
close(pip[0]);
if (pip[1] != 1) {
close(1);
copyfd(pip[1], 1);
close(pip[1]);
}
}
evaltree(lp->n, EV_EXIT);
}
if (prevfd >= 0)
close(prevfd);
prevfd = pip[0];
close(pip[1]);
}
INTON;
if (n->npipe.backgnd == 0) {
INTOFF;
exitstatus = waitforjob(jp);
TRACE(("evalpipe: job done exit status %d\n", exitstatus));
INTON;
}
}
/*
* Execute a command inside back quotes. If it's a builtin command, we
* want to save its output in a block obtained from malloc. Otherwise
* we fork off a subprocess and get the output of the command via a pipe.
* Should be called with interrupts off.
*/
void
evalbackcmd(n, result)
union node *n;
struct backcmd *result;
{
int pip[2];
struct job *jp;
struct stackmark smark; /* unnecessary */
setstackmark(&smark);
result->fd = -1;
result->buf = NULL;
result->nleft = 0;
result->jp = NULL;
if (n == NULL) {
/* `` */
} else
if (n->type == NCMD) {
evalcommand(n, EV_BACKCMD, result);
} else {
if (pipe(pip) < 0)
error("Pipe call failed");
jp = makejob(n, 1);
if (forkshell(jp, n, FORK_NOJOB) == 0) {
FORCEINTON;
close(pip[0]);
if (pip[1] != 1) {
close(1);
copyfd(pip[1], 1);
close(pip[1]);
}
evaltree(n, EV_EXIT);
}
close(pip[1]);
result->fd = pip[0];
result->jp = jp;
}
popstackmark(&smark);
TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
result->fd, result->buf, result->nleft, result->jp));
}
/*
* Execute a simple command.
*/
STATIC void
evalcommand(cmd, flags, backcmd)
union node *cmd;
struct backcmd *backcmd;
{
struct stackmark smark;
union node *argp;
struct arglist arglist;
struct arglist varlist;
char **argv;
int argc;
char **envp;
int varflag;
struct strlist *sp;
register char *p;
int mode;
int pip[2];
struct cmdentry cmdentry;
struct job *jp;
struct jmploc jmploc;
struct jmploc *volatile savehandler;
char *volatile savecmdname;
volatile struct shparam saveparam;
struct localvar *volatile savelocalvars;
volatile int e;
char *lastarg;
/* First expand the arguments. */
TRACE(("evalcommand(0x%x, %d) called\n", (int)cmd, flags));
setstackmark(&smark);
arglist.lastp = &arglist.list;
varlist.lastp = &varlist.list;
varflag = 1;
for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
p = argp->narg.text;
if (varflag && is_name(*p)) {
do {
p++;
} while (is_in_name(*p));
if (*p == '=') {
expandarg(argp, &varlist, 0);
continue;
}
}
expandarg(argp, &arglist, 1);
varflag = 0;
}
*arglist.lastp = NULL;
*varlist.lastp = NULL;
expredir(cmd->ncmd.redirect);
argc = 0;
for (sp = arglist.list ; sp ; sp = sp->next)
argc++;
argv = stalloc(sizeof (char *) * (argc + 1));
for (sp = arglist.list ; sp ; sp = sp->next)
*argv++ = sp->text;
*argv = NULL;
lastarg = NULL;
if (iflag && funcnest == 0 && argc > 0)
lastarg = argv[-1];
argv -= argc;
/* Print the command if xflag is set. */
if (xflag == 1) {
outc('+', &errout);
for (sp = varlist.list ; sp ; sp = sp->next) {
outc(' ', &errout);
out2str(sp->text);
}
for (sp = arglist.list ; sp ; sp = sp->next) {
outc(' ', &errout);
out2str(sp->text);
}
outc('\n', &errout);
flushout(&errout);
}
/* Now locate the command. */
if (argc == 0) {
cmdentry.cmdtype = CMDBUILTIN;
cmdentry.u.index = BLTINCMD;
} else {
find_command(argv[0], &cmdentry, 1);
if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */
exitstatus = 2;
flushout(&errout);
popstackmark(&smark);
return;
}
/* implement the bltin builtin here */
if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) {
for (;;) {
argv++;
if (--argc == 0)
break;
if ((cmdentry.u.index = find_builtin(*argv)) < 0) {
outfmt(&errout, "%s: not found\n", *argv);
exitstatus = 2;
flushout(&errout);
popstackmark(&smark);
return;
}
if (cmdentry.u.index != BLTINCMD)
break;
}
}
}
/* Fork off a child process if necessary. */
if (cmd->ncmd.backgnd
|| cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0
|| (flags & EV_BACKCMD) != 0
&& (cmdentry.cmdtype != CMDBUILTIN
|| cmdentry.u.index == DOTCMD
|| cmdentry.u.index == EVALCMD)) {
jp = makejob(cmd, 1);
mode = cmd->ncmd.backgnd;
if (flags & EV_BACKCMD) {
mode = FORK_NOJOB;
if (pipe(pip) < 0)
error("Pipe call failed");
}
if (forkshell(jp, cmd, mode) != 0)
goto parent; /* at end of routine */
if (flags & EV_BACKCMD) {
FORCEINTON;
close(pip[0]);
if (pip[1] != 1) {
close(1);
copyfd(pip[1], 1);
close(pip[1]);
}
}
flags |= EV_EXIT;
}
/* This is the child process if a fork occurred. */
/* Execute the command. */
if (cmdentry.cmdtype == CMDFUNCTION) {
trputs("Shell function: "); trargs(argv);
redirect(cmd->ncmd.redirect, REDIR_PUSH);
saveparam = shellparam;
shellparam.malloc = 0;
shellparam.nparam = argc - 1;
shellparam.p = argv + 1;
shellparam.optnext = NULL;
INTOFF;
savelocalvars = localvars;
localvars = NULL;
INTON;
if (setjmp(jmploc.loc)) {
if (exception == EXSHELLPROC)
freeparam((struct shparam *)&saveparam);
else {
freeparam(&shellparam);
shellparam = saveparam;
}
poplocalvars();
localvars = savelocalvars;
handler = savehandler;
longjmp(handler->loc, 1);
}
savehandler = handler;
handler = &jmploc;
for (sp = varlist.list ; sp ; sp = sp->next)
mklocal(sp->text);
funcnest++;
evaltree(cmdentry.u.func, 0);
funcnest--;
INTOFF;
poplocalvars();
localvars = savelocalvars;
freeparam(&shellparam);
shellparam = saveparam;
handler = savehandler;
popredir();
INTON;
if (evalskip == SKIPFUNC) {
evalskip = 0;
skipcount = 0;
}
if (flags & EV_EXIT)
exitshell(exitstatus);
} else if (cmdentry.cmdtype == CMDBUILTIN) {
trputs("builtin command: "); trargs(argv);
mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH;
if (flags == EV_BACKCMD) {
memout.nleft = 0;
memout.nextc = memout.buf;
memout.bufsize = 64;
mode |= REDIR_BACKQ;
}
redirect(cmd->ncmd.redirect, mode);
savecmdname = commandname;
cmdenviron = varlist.list;
e = -1;
if (setjmp(jmploc.loc)) {
e = exception;
exitstatus = (e == EXINT)? SIGINT+128 : 2;
goto cmddone;
}
savehandler = handler;
handler = &jmploc;
commandname = argv[0];
argptr = argv + 1;
optptr = NULL; /* initialize nextopt */
exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv);
flushall();
cmddone:
out1 = &output;
out2 = &errout;
freestdout();
if (e != EXSHELLPROC) {
commandname = savecmdname;
if (flags & EV_EXIT) {
exitshell(exitstatus);
}
}
handler = savehandler;
if (e != -1) {
if (e != EXERROR || cmdentry.u.index == BLTINCMD
|| cmdentry.u.index == DOTCMD
|| cmdentry.u.index == EVALCMD
|| cmdentry.u.index == EXECCMD)
exraise(e);
FORCEINTON;
}
if (cmdentry.u.index != EXECCMD)
popredir();
if (flags == EV_BACKCMD) {
backcmd->buf = memout.buf;
backcmd->nleft = memout.nextc - memout.buf;
memout.buf = NULL;
}
} else {
trputs("normal command: "); trargs(argv);
clearredir();
redirect(cmd->ncmd.redirect, 0);
if (varlist.list) {
p = stalloc(strlen(pathval()) + 1);
scopy(pathval(), p);
} else {
p = pathval();
}
for (sp = varlist.list ; sp ; sp = sp->next)
setvareq(sp->text, VEXPORT|VSTACK);
envp = environment();
shellexec(argv, envp, p, cmdentry.u.index);
/*NOTREACHED*/
}
goto out;
parent: /* parent process gets here (if we forked) */
if (mode == 0) { /* argument to fork */
INTOFF;
exitstatus = waitforjob(jp);
INTON;
} else if (mode == 2) {
backcmd->fd = pip[0];
close(pip[1]);
backcmd->jp = jp;
}
out:
if (lastarg)
setvar("_", lastarg, 0);
popstackmark(&smark);
}
/*
* Search for a command. This is called before we fork so that the
* location of the command will be available in the parent as well as
* the child. The check for "goodname" is an overly conservative
* check that the name will not be subject to expansion.
*/
STATIC void
prehash(n)
union node *n;
{
struct cmdentry entry;
if (n->type == NCMD && goodname(n->ncmd.args->narg.text))
find_command(n->ncmd.args->narg.text, &entry, 0);
}
/*
* Builtin commands. Builtin commands whose functions are closely
* tied to evaluation are implemented here.
*/
/*
* No command given, or a bltin command with no arguments. Set the
* specified variables.
*/
bltincmd(argc, argv) char **argv; {
listsetvar(cmdenviron);
return exitstatus;
}
/*
* Handle break and continue commands. Break, continue, and return are
* all handled by setting the evalskip flag. The evaluation routines
* above all check this flag, and if it is set they start skipping
* commands rather than executing them. The variable skipcount is
* the number of loops to break/continue, or the number of function
* levels to return. (The latter is always 1.) It should probably
* be an error to break out of more loops than exist, but it isn't
* in the standard shell so we don't make it one here.
*/
breakcmd(argc, argv) char **argv; {
int n;
n = 1;
if (argc > 1)
n = number(argv[1]);
if (n > loopnest)
n = loopnest;
if (n > 0) {
evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
skipcount = n;
}
return 0;
}
/*
* The return command.
*/
returncmd(argc, argv) char **argv; {
int ret;
ret = exitstatus;
if (argc > 1)
ret = number(argv[1]);
if (funcnest) {
evalskip = SKIPFUNC;
skipcount = 1;
}
return ret;
}
truecmd(argc, argv) char **argv; {
return strcmp(argv[0], "false") == 0 ? 1 : 0;
}
execcmd(argc, argv) char **argv; {
if (argc > 1) {
iflag = 0; /* exit on error */
setinteractive(0);
#if JOBS
jflag = 0;
setjobctl(0);
#endif
shellexec(argv + 1, environment(), pathval(), 0);
}
return 0;
}

65
commands/ash/eval.h Executable file
View file

@ -0,0 +1,65 @@
/*-
* Copyright (c) 1991 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Kenneth Almquist.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)eval.h 5.2 (Berkeley) 4/12/91
*/
extern char *commandname; /* currently executing command */
extern int exitstatus; /* exit status of last command */
extern struct strlist *cmdenviron; /* environment for builtin command */
struct backcmd { /* result of evalbackcmd */
int fd; /* file descriptor to read from */
char *buf; /* buffer */
int nleft; /* number of chars in buffer */
struct job *jp; /* job structure for command */
};
#ifdef __STDC__
void evalstring(char *);
union node; /* BLETCH for ansi C */
void evaltree(union node *, int);
void evalbackcmd(union node *, struct backcmd *);
#else
void evalstring();
void evaltree();
void evalbackcmd();
#endif
/* in_function returns nonzero if we are currently evaluating a function */
#define in_function() funcnest
extern int funcnest;

824
commands/ash/exec.c Executable file
View file

@ -0,0 +1,824 @@
/*-
* Copyright (c) 1991 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Kenneth Almquist.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char sccsid[] = "@(#)exec.c 5.2 (Berkeley) 3/13/91";
#endif /* not lint */
/*
* When commands are first encountered, they are entered in a hash table.
* This ensures that a full path search will not have to be done for them
* on each invocation.
*
* We should investigate converting to a linear search, even though that
* would make the command name "hash" a misnomer.
*/
#include "shell.h"
#include "main.h"
#include "nodes.h"
#include "parser.h"
#include "redir.h"
#include "eval.h"
#include "exec.h"
#include "builtins.h"
#include "var.h"
#include "options.h"
#include "input.h"
#include "output.h"
#include "syntax.h"
#include "memalloc.h"
#include "error.h"
#include "init.h"
#include "mystring.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <limits.h>
#define CMDTABLESIZE 31 /* should be prime */
#define ARB 1 /* actual size determined at run time */
struct tblentry {
struct tblentry *next; /* next entry in hash chain */
union param param; /* definition of builtin function */
short cmdtype; /* index identifying command */
char rehash; /* if set, cd done since entry created */
char cmdname[ARB]; /* name of command */
};
STATIC struct tblentry *cmdtable[CMDTABLESIZE];
STATIC int builtinloc = -1; /* index in path of %builtin, or -1 */
#ifdef __STDC__
STATIC void tryexec(char *, char **, char **);
STATIC void execinterp(char **, char **);
STATIC void printentry(struct tblentry *);
STATIC void clearcmdentry(int);
STATIC struct tblentry *cmdlookup(char *, int);
STATIC void delete_cmd_entry(void);
#else
STATIC void tryexec();
STATIC void execinterp();
STATIC void printentry();
STATIC void clearcmdentry();
STATIC struct tblentry *cmdlookup();
STATIC void delete_cmd_entry();
#endif
/*
* Exec a program. Never returns. If you change this routine, you may
* have to change the find_command routine as well.
*/
void
shellexec(argv, envp, path, index)
char **argv, **envp;
char *path;
{
char *cmdname;
int e;
if (strchr(argv[0], '/') != NULL) {
tryexec(argv[0], argv, envp);
e = errno;
} else {
e = ENOENT;
while ((cmdname = padvance(&path, argv[0])) != NULL) {
if (--index < 0 && pathopt == NULL) {
tryexec(cmdname, argv, envp);
if (errno != ENOENT && errno != ENOTDIR)
e = errno;
}
stunalloc(cmdname);
}
}
error2(argv[0], errmsg(e, E_EXEC));
}
STATIC void
tryexec(cmd, argv, envp)
char *cmd;
char **argv;
char **envp;
{
int e;
char *p;
#ifdef SYSV
do {
execve(cmd, argv, envp);
} while (errno == EINTR);
#else
execve(cmd, argv, envp);
#endif
#if HASHBANG
e = errno;
if (e == ENOEXEC) {
initshellproc();
setinputfile(cmd, 0);
commandname = arg0 = savestr(argv[0]);
#ifndef BSD
pgetc(); pungetc(); /* fill up input buffer */
p = parsenextc;
if (parsenleft > 2 && p[0] == '#' && p[1] == '!') {
argv[0] = cmd;
execinterp(argv, envp);
}
#endif
setparam(argv + 1);
exraise(EXSHELLPROC);
/*NOTREACHED*/
}
errno = e;
#endif
}
#if !defined(BSD) && HASHBANG
/*
* Execute an interpreter introduced by "#!", for systems where this
* feature has not been built into the kernel. If the interpreter is
* the shell, return (effectively ignoring the "#!"). If the execution
* of the interpreter fails, exit.
*
* This code peeks inside the input buffer in order to avoid actually
* reading any input. It would benefit from a rewrite.
*/
#define NEWARGS 5
STATIC void
execinterp(argv, envp)
char **argv, **envp;
{
int n;
char *inp;
char *outp;
char c;
char *p;
char **ap;
char *newargs[NEWARGS];
int i;
char **ap2;
char **new;
n = parsenleft - 2;
inp = parsenextc + 2;
ap = newargs;
for (;;) {
while (--n >= 0 && (*inp == ' ' || *inp == '\t'))
inp++;
if (n < 0)
goto bad;
if ((c = *inp++) == '\n')
break;
if (ap == &newargs[NEWARGS])
bad: error("Bad #! line");
STARTSTACKSTR(outp);
do {
STPUTC(c, outp);
} while (--n >= 0 && (c = *inp++) != ' ' && c != '\t' && c != '\n');
STPUTC('\0', outp);
n++, inp--;
*ap++ = grabstackstr(outp);
}
#if !__minix
if (ap == newargs + 1) { /* if no args, maybe no exec is needed */
p = newargs[0];
for (;;) {
if (equal(p, "sh") || equal(p, "ash")) {
return;
}
while (*p != '/') {
if (*p == '\0')
goto break2;
p++;
}
p++;
}
break2:;
}
#endif
i = (char *)ap - (char *)newargs; /* size in bytes */
if (i == 0)
error("Bad #! line");
for (ap2 = argv ; *ap2++ != NULL ; );
new = ckmalloc(i + ((char *)ap2 - (char *)argv));
ap = newargs, ap2 = new;
while ((i -= sizeof (char **)) >= 0)
*ap2++ = *ap++;
ap = argv;
while (*ap2++ = *ap++);
shellexec(new, envp, pathval(), 0);
}
#endif
/*
* Do a path search. The variable path (passed by reference) should be
* set to the start of the path before the first call; padvance will update
* this value as it proceeds. Successive calls to padvance will return
* the possible path expansions in sequence. If an option (indicated by
* a percent sign) appears in the path entry then the global variable
* pathopt will be set to point to it; otherwise pathopt will be set to
* NULL.
*/
char *pathopt;
char *
padvance(path, name)
char **path;
char *name;
{
register char *p, *q;
char *start;
int len;
if (*path == NULL)
return NULL;
start = *path;
for (p = start ; *p && *p != ':' && *p != '%' ; p++);
len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
while (stackblocksize() < len)
growstackblock();
q = stackblock();
if (p != start) {
bcopy(start, q, p - start);
q += p - start;
*q++ = '/';
}
strcpy(q, name);
pathopt = NULL;
if (*p == '%') {
pathopt = ++p;
while (*p && *p != ':') p++;
}
if (*p == ':')
*path = p + 1;
else
*path = NULL;
return stalloc(len);
}
/*** Command hashing code ***/
hashcmd(argc, argv) char **argv; {
struct tblentry **pp;
struct tblentry *cmdp;
int c;
int verbose;
struct cmdentry entry;
char *name;
if (argc <= 1) {
for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
printentry(cmdp);
}
}
return 0;
}
verbose = 0;
while ((c = nextopt("rv")) != '\0') {
if (c == 'r') {
clearcmdentry(0);
} else if (c == 'v') {
verbose++;
}
}
while ((name = *argptr) != NULL) {
if ((cmdp = cmdlookup(name, 0)) != NULL
&& (cmdp->cmdtype == CMDNORMAL
|| cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
delete_cmd_entry();
find_command(name, &entry, 1);
if (verbose) {
if (entry.cmdtype != CMDUNKNOWN) { /* if no error msg */
cmdp = cmdlookup(name, 0);
printentry(cmdp);
}
flushall();
}
argptr++;
}
return 0;
}
STATIC void
printentry(cmdp)
struct tblentry *cmdp;
{
int index;
char *path;
char *name;
if (cmdp->cmdtype == CMDNORMAL) {
index = cmdp->param.index;
path = pathval();
do {
name = padvance(&path, cmdp->cmdname);
stunalloc(name);
} while (--index >= 0);
out1str(name);
} else if (cmdp->cmdtype == CMDBUILTIN) {
out1fmt("builtin %s", cmdp->cmdname);
} else if (cmdp->cmdtype == CMDFUNCTION) {
out1fmt("function %s", cmdp->cmdname);
#if DEBUG
} else {
error("internal error: cmdtype %d", cmdp->cmdtype);
#endif
}
if (cmdp->rehash)
out1c('*');
out1c('\n');
}
/*
* Resolve a command name. If you change this routine, you may have to
* change the shellexec routine as well.
*/
void
find_command(name, entry, printerr)
char *name;
struct cmdentry *entry;
{
struct tblentry *cmdp;
int index;
int prev;
char *path;
char *fullname;
struct stat statb;
int e;
int i;
/* If name contains a slash, don't use the hash table */
if (strchr(name, '/') != NULL) {
entry->cmdtype = CMDNORMAL;
entry->u.index = 0;
return;
}
/* If name is in the table, and not invalidated by cd, we're done */
if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0)
goto success;
/* If %builtin not in path, check for builtin next */
if (builtinloc < 0 && (i = find_builtin(name)) >= 0) {
INTOFF;
cmdp = cmdlookup(name, 1);
cmdp->cmdtype = CMDBUILTIN;
cmdp->param.index = i;
INTON;
goto success;
}
/* We have to search path. */
prev = -1; /* where to start */
if (cmdp) { /* doing a rehash */
if (cmdp->cmdtype == CMDBUILTIN)
prev = builtinloc;
else
prev = cmdp->param.index;
}
path = pathval();
e = ENOENT;
index = -1;
loop:
while ((fullname = padvance(&path, name)) != NULL) {
stunalloc(fullname);
index++;
if (pathopt) {
if (prefix("builtin", pathopt)) {
if ((i = find_builtin(name)) < 0)
goto loop;
INTOFF;
cmdp = cmdlookup(name, 1);
cmdp->cmdtype = CMDBUILTIN;
cmdp->param.index = i;
INTON;
goto success;
} else if (prefix("func", pathopt)) {
/* handled below */
} else {
goto loop; /* ignore unimplemented options */
}
}
/* if rehash, don't redo absolute path names */
if (fullname[0] == '/' && index <= prev) {
if (index < prev)
goto loop;
TRACE(("searchexec \"%s\": no change\n", name));
goto success;
}
while (stat(fullname, &statb) < 0) {
#ifdef SYSV
if (errno == EINTR)
continue;
#endif
if (errno != ENOENT && errno != ENOTDIR)
e = errno;
goto loop;
}
e = EACCES; /* if we fail, this will be the error */
if ((statb.st_mode & S_IFMT) != S_IFREG)
goto loop;
if (pathopt) { /* this is a %func directory */
stalloc(strlen(fullname) + 1);
readcmdfile(fullname);
if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
error("%s not defined in %s", name, fullname);
stunalloc(fullname);
goto success;
}
if (statb.st_uid == geteuid()) {
if ((statb.st_mode & 0100) == 0)
goto loop;
} else if (statb.st_gid == getegid()) {
if ((statb.st_mode & 010) == 0)
goto loop;
} else {
#if __minix_vmd || defined(BSD)
gid_t group_list[NGROUPS_MAX];
int ngroups, i;
ngroups = getgroups(NGROUPS_MAX, group_list);
for (i = 0; i < ngroups; i++) {
if (statb.st_gid == group_list[i]) break;
}
if (i < ngroups) {
if ((statb.st_mode & 010) == 0)
goto loop;
} else
#endif
if ((statb.st_mode & 01) == 0)
goto loop;
}
TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
INTOFF;
cmdp = cmdlookup(name, 1);
cmdp->cmdtype = CMDNORMAL;
cmdp->param.index = index;
INTON;
goto success;
}
/* We failed. If there was an entry for this command, delete it */
if (cmdp)
delete_cmd_entry();
if (printerr)
outfmt(out2, "%s: %s\n", name, errmsg(e, E_EXEC));
entry->cmdtype = CMDUNKNOWN;
return;
success:
cmdp->rehash = 0;
entry->cmdtype = cmdp->cmdtype;
entry->u = cmdp->param;
}
/*
* Search the table of builtin commands.
*/
int
find_builtin(name)
char *name;
{
const register struct builtincmd *bp;
for (bp = builtincmd ; bp->name ; bp++) {
if (*bp->name == *name && equal(bp->name, name))
return bp->code;
}
return -1;
}
/*
* Called when a cd is done. Marks all commands so the next time they
* are executed they will be rehashed.
*/
void
hashcd() {
struct tblentry **pp;
struct tblentry *cmdp;
for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
if (cmdp->cmdtype == CMDNORMAL
|| cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)
cmdp->rehash = 1;
}
}
}
/*
* Called before PATH is changed. The argument is the new value of PATH;
* pathval() still returns the old value at this point. Called with
* interrupts off.
*/
void
changepath(newval)
char *newval;
{
char *old, *new;
int index;
int firstchange;
int bltin;
old = pathval();
new = newval;
firstchange = 9999; /* assume no change */
index = 0;
bltin = -1;
for (;;) {
if (*old != *new) {
firstchange = index;
if (*old == '\0' && *new == ':'
|| *old == ':' && *new == '\0')
firstchange++;
old = new; /* ignore subsequent differences */
}
if (*new == '\0')
break;
if (*new == '%' && bltin < 0 && prefix("builtin", new + 1))
bltin = index;
if (*new == ':') {
index++;
}
new++, old++;
}
if (builtinloc < 0 && bltin >= 0)
builtinloc = bltin; /* zap builtins */
if (builtinloc >= 0 && bltin < 0)
firstchange = 0;
clearcmdentry(firstchange);
builtinloc = bltin;
}
/*
* Clear out command entries. The argument specifies the first entry in
* PATH which has changed.
*/
STATIC void
clearcmdentry(firstchange) {
struct tblentry **tblp;
struct tblentry **pp;
struct tblentry *cmdp;
INTOFF;
for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
pp = tblp;
while ((cmdp = *pp) != NULL) {
if (cmdp->cmdtype == CMDNORMAL && cmdp->param.index >= firstchange
|| cmdp->cmdtype == CMDBUILTIN && builtinloc >= firstchange) {
*pp = cmdp->next;
ckfree(cmdp);
} else {
pp = &cmdp->next;
}
}
}
INTON;
}
/*
* Delete all functions.
*/
#ifdef mkinit
MKINIT void deletefuncs();
SHELLPROC {
deletefuncs();
}
#endif
void
deletefuncs() {
struct tblentry **tblp;
struct tblentry **pp;
struct tblentry *cmdp;
INTOFF;
for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
pp = tblp;
while ((cmdp = *pp) != NULL) {
if (cmdp->cmdtype == CMDFUNCTION) {
*pp = cmdp->next;
freefunc(cmdp->param.func);
ckfree(cmdp);
} else {
pp = &cmdp->next;
}
}
}
INTON;
}
/*
* Locate a command in the command hash table. If "add" is nonzero,
* add the command to the table if it is not already present. The
* variable "lastcmdentry" is set to point to the address of the link
* pointing to the entry, so that delete_cmd_entry can delete the
* entry.
*/
struct tblentry **lastcmdentry;
STATIC struct tblentry *
cmdlookup(name, add)
char *name;
{
int hashval;
register char *p;
struct tblentry *cmdp;
struct tblentry **pp;
p = name;
hashval = *p << 4;
while (*p)
hashval += *p++;
hashval &= 0x7FFF;
pp = &cmdtable[hashval % CMDTABLESIZE];
for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
if (equal(cmdp->cmdname, name))
break;
pp = &cmdp->next;
}
if (add && cmdp == NULL) {
INTOFF;
cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
+ strlen(name) + 1);
cmdp->next = NULL;
cmdp->cmdtype = CMDUNKNOWN;
cmdp->rehash = 0;
strcpy(cmdp->cmdname, name);
INTON;
}
lastcmdentry = pp;
return cmdp;
}
/*
* Delete the command entry returned on the last lookup.
*/
STATIC void
delete_cmd_entry() {
struct tblentry *cmdp;
INTOFF;
cmdp = *lastcmdentry;
*lastcmdentry = cmdp->next;
ckfree(cmdp);
INTON;
}
#ifdef notdef
void
getcmdentry(name, entry)
char *name;
struct cmdentry *entry;
{
struct tblentry *cmdp = cmdlookup(name, 0);
if (cmdp) {
entry->u = cmdp->param;
entry->cmdtype = cmdp->cmdtype;
} else {
entry->cmdtype = CMDUNKNOWN;
entry->u.index = 0;
}
}
#endif
/*
* Add a new command entry, replacing any existing command entry for
* the same name.
*/
void
addcmdentry(name, entry)
char *name;
struct cmdentry *entry;
{
struct tblentry *cmdp;
INTOFF;
cmdp = cmdlookup(name, 1);
if (cmdp->cmdtype == CMDFUNCTION) {
freefunc(cmdp->param.func);
}
cmdp->cmdtype = entry->cmdtype;
cmdp->param = entry->u;
INTON;
}
/*
* Define a shell function.
*/
void
defun(name, func)
char *name;
union node *func;
{
struct cmdentry entry;
INTOFF;
entry.cmdtype = CMDFUNCTION;
entry.u.func = copyfunc(func);
addcmdentry(name, &entry);
INTON;
}
/*
* Delete a function if it exists.
*/
void
unsetfunc(name)
char *name;
{
struct tblentry *cmdp;
if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
freefunc(cmdp->param.func);
delete_cmd_entry();
}
}

75
commands/ash/exec.h Executable file
View file

@ -0,0 +1,75 @@
/*-
* Copyright (c) 1991 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Kenneth Almquist.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)exec.h 5.1 (Berkeley) 3/7/91
*/
/* values of cmdtype */
#define CMDUNKNOWN -1 /* no entry in table for command */
#define CMDNORMAL 0 /* command is an executable program */
#define CMDBUILTIN 1 /* command is a shell builtin */
#define CMDFUNCTION 2 /* command is a shell function */
struct cmdentry {
int cmdtype;
union param {
int index;
union node *func;
} u;
};
extern char *pathopt; /* set by padvance */
#ifdef __STDC__
void shellexec(char **, char **, char *, int);
char *padvance(char **, char *);
void find_command(char *, struct cmdentry *, int);
int find_builtin(char *);
void hashcd(void);
void changepath(char *);
void defun(char *, union node *);
void unsetfunc(char *);
#else
void shellexec();
char *padvance();
void find_command();
int find_builtin();
void hashcd();
void changepath();
void defun();
void unsetfunc();
#endif

1156
commands/ash/expand.c Executable file

File diff suppressed because it is too large Load diff

63
commands/ash/expand.h Executable file
View file

@ -0,0 +1,63 @@
/*-
* Copyright (c) 1991 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Kenneth Almquist.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)expand.h 5.1 (Berkeley) 3/7/91
*/
struct strlist {
struct strlist *next;
char *text;
};
struct arglist {
struct strlist *list;
struct strlist **lastp;
};
#ifdef __STDC__
union node;
void expandarg(union node *, struct arglist *, int);
void expandhere(union node *, int);
int patmatch(char *, char *);
void rmescapes(char *);
int casematch(union node *, char *);
#else
void expandarg();
void expandhere();
int patmatch();
void rmescapes();
int casematch();
#endif

49
commands/ash/funcs/cmv Executable file
View file

@ -0,0 +1,49 @@
# Copyright (c) 1991 The Regents of the University of California.
# All rights reserved.
#
# This code is derived from software contributed to Berkeley by
# Kenneth Almquist.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. All advertising materials mentioning features or use of this software
# must display the following acknowledgement:
# This product includes software developed by the University of
# California, Berkeley and its contributors.
# 4. Neither the name of the University nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# @(#)cmv 5.1 (Berkeley) 3/7/91
# Conditional move--don't replace an existing file.
cmv() {
if test $# != 2
then echo "cmv: arg count"
return 2
fi
if test -f "$2" -o -w "$2"
then echo "$2 exists"
return 2
fi
/bin/mv "$1" "$2"
}

73
commands/ash/funcs/dirs Executable file
View file

@ -0,0 +1,73 @@
# Copyright (c) 1991 The Regents of the University of California.
# All rights reserved.
#
# This code is derived from software contributed to Berkeley by
# Kenneth Almquist.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. All advertising materials mentioning features or use of this software
# must display the following acknowledgement:
# This product includes software developed by the University of
# California, Berkeley and its contributors.
# 4. Neither the name of the University nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# @(#)dirs 5.1 (Berkeley) 3/7/91
# pushd, popd, and dirs --- written by Chris Bertin
# Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris
# as modified by Patrick Elam of GTRI and Kenneth Almquist at UW
pushd () {
SAVE=`pwd`
if [ "$1" = "" ]
then if [ "$DSTACK" = "" ]
then echo "pushd: directory stack empty."
return 1
fi
set $DSTACK
cd $1 || return
shift 1
DSTACK="$*"
else cd $1 > /dev/null || return
fi
DSTACK="$SAVE $DSTACK"
dirs
}
popd () {
if [ "$DSTACK" = "" ]
then echo "popd: directory stack empty."
return 1
fi
set $DSTACK
cd $1
shift
DSTACK=$*
dirs
}
dirs () {
echo "`pwd` $DSTACK"
return 0
}

49
commands/ash/funcs/kill Executable file
View file

@ -0,0 +1,49 @@
# Copyright (c) 1991 The Regents of the University of California.
# All rights reserved.
#
# This code is derived from software contributed to Berkeley by
# Kenneth Almquist.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. All advertising materials mentioning features or use of this software
# must display the following acknowledgement:
# This product includes software developed by the University of
# California, Berkeley and its contributors.
# 4. Neither the name of the University nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# @(#)kill 5.1 (Berkeley) 3/7/91
# Convert job names to process ids and then run /bin/kill.
kill() {
local args x
args=
for x in "$@"
do case $x in
%*) x=`jobid "$x"` ;;
esac
args="$args $x"
done
/bin/kill $args
}

38
commands/ash/funcs/login Executable file
View file

@ -0,0 +1,38 @@
# Copyright (c) 1991 The Regents of the University of California.
# All rights reserved.
#
# This code is derived from software contributed to Berkeley by
# Kenneth Almquist.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. All advertising materials mentioning features or use of this software
# must display the following acknowledgement:
# This product includes software developed by the University of
# California, Berkeley and its contributors.
# 4. Neither the name of the University nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# @(#)login 5.1 (Berkeley) 3/7/91
# replaces the login builtin in the BSD shell
login () exec login "$@"

37
commands/ash/funcs/newgrp Executable file
View file

@ -0,0 +1,37 @@
# Copyright (c) 1991 The Regents of the University of California.
# All rights reserved.
#
# This code is derived from software contributed to Berkeley by
# Kenneth Almquist.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. All advertising materials mentioning features or use of this software
# must display the following acknowledgement:
# This product includes software developed by the University of
# California, Berkeley and its contributors.
# 4. Neither the name of the University nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# @(#)newgrp 5.1 (Berkeley) 3/7/91
newgrp() exec newgrp "$@"

73
commands/ash/funcs/popd Executable file
View file

@ -0,0 +1,73 @@
# Copyright (c) 1991 The Regents of the University of California.
# All rights reserved.
#
# This code is derived from software contributed to Berkeley by
# Kenneth Almquist.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. All advertising materials mentioning features or use of this software
# must display the following acknowledgement:
# This product includes software developed by the University of
# California, Berkeley and its contributors.
# 4. Neither the name of the University nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# @(#)popd 5.1 (Berkeley) 3/7/91
# pushd, popd, and dirs --- written by Chris Bertin
# Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris
# as modified by Patrick Elam of GTRI and Kenneth Almquist at UW
pushd () {
SAVE=`pwd`
if [ "$1" = "" ]
then if [ "$DSTACK" = "" ]
then echo "pushd: directory stack empty."
return 1
fi
set $DSTACK
cd $1 || return
shift 1
DSTACK="$*"
else cd $1 > /dev/null || return
fi
DSTACK="$SAVE $DSTACK"
dirs
}
popd () {
if [ "$DSTACK" = "" ]
then echo "popd: directory stack empty."
return 1
fi
set $DSTACK
cd $1
shift
DSTACK=$*
dirs
}
dirs () {
echo "`pwd` $DSTACK"
return 0
}

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