Initial revision
This commit is contained in:
commit
9865aeaa79
2264 changed files with 411685 additions and 0 deletions
32
LICENSE
Executable file
32
LICENSE
Executable 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
51
Makefile
Executable 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
116
boot/Makefile
Executable 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
25
boot/a.out2com
Executable 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
127
boot/addaout.c
Normal 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
1930
boot/boot.c
Executable file
File diff suppressed because it is too large
Load diff
209
boot/boot.h
Executable file
209
boot/boot.h
Executable 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
231
boot/bootblock.s
Executable 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
1497
boot/boothead.s
Executable file
File diff suppressed because it is too large
Load diff
712
boot/bootimage.c
Executable file
712
boot/bootimage.c
Executable 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
1369
boot/doshead.s
Executable file
File diff suppressed because it is too large
Load diff
13
boot/image.h
Executable file
13
boot/image.h
Executable 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
833
boot/installboot.c
Executable 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
261
boot/jumpboot.s
Executable 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
218
boot/masterboot.s
Executable 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
137
boot/mkfhead.s
Executable 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
180
boot/mkfile.c
Executable 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
350
boot/rawfs.c
Executable 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
43
boot/rawfs.h
Executable 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
47
commands/Makefile
Executable 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
56
commands/aal/Makefile
Executable 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
25
commands/aal/arch.h
Executable 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
800
commands/aal/archiver.c
Executable 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
9
commands/aal/byte_order.h
Executable 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
112
commands/aal/format.c
Executable 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
19
commands/aal/local.h
Executable 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
67
commands/aal/long2str.c
Executable 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
76
commands/aal/object.h
Executable 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
126
commands/aal/out.h
Executable 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
7
commands/aal/param.h
Executable 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
42
commands/aal/print.c
Executable 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
34
commands/aal/ranlib.h
Executable 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
254
commands/aal/rd.c
Executable 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
35
commands/aal/rd_arhdr.c
Executable 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
32
commands/aal/rd_bytes.c
Executable 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
15
commands/aal/rd_unsig2.c
Executable 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
42
commands/aal/sprint.c
Executable 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
24
commands/aal/system.c
Executable 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
47
commands/aal/system.h
Executable 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
16
commands/aal/varargs.h
Executable 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
28
commands/aal/wr_arhdr.c
Executable 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
30
commands/aal/wr_bytes.c
Executable 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
14
commands/aal/wr_int2.c
Executable 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
15
commands/aal/wr_long.c
Executable 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
36
commands/aal/wr_ranlib.c
Executable 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
17
commands/aal/write.c
Executable 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
63
commands/advent/Makefile
Executable 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
1357
commands/advent/advcave.h
Executable file
File diff suppressed because it is too large
Load diff
71
commands/advent/advdec.h
Executable file
71
commands/advent/advdec.h
Executable 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
136
commands/advent/advent.c
Executable 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
405
commands/advent/advent.h
Executable 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
827
commands/advent/advent1.txt
Executable 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
514
commands/advent/advent2.txt
Executable 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
539
commands/advent/advent3.txt
Executable 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
1068
commands/advent/advent4.txt
Executable file
File diff suppressed because it is too large
Load diff
141
commands/advent/database.c
Executable file
141
commands/advent/database.c
Executable 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
676
commands/advent/english.c
Executable 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
264
commands/advent/initial.c
Executable 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
597
commands/advent/itverb.c
Executable 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
199
commands/advent/score.c
Executable 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
99
commands/advent/setup.c
Executable 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
336
commands/advent/travel.c
Executable 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
729
commands/advent/turn.c
Executable 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
749
commands/advent/utility.c
Executable 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
2142
commands/advent/verb.c
Executable file
File diff suppressed because it is too large
Load diff
594
commands/advent/vocab.c
Executable file
594
commands/advent/vocab.c
Executable 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
101
commands/ash/Makefile
Executable 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
348
commands/ash/TOUR
Executable 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
40
commands/ash/bltin/LICENSE
Executable 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
25
commands/ash/bltin/binary_op
Executable 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
40
commands/ash/bltin/bltin.h
Executable 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
88
commands/ash/bltin/catf.c
Executable 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
74
commands/ash/bltin/echo.c
Executable 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
23
commands/ash/bltin/error.c
Executable 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
481
commands/ash/bltin/expr.c
Executable 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
27
commands/ash/bltin/line.c
Executable 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
71
commands/ash/bltin/makefile.not
Executable 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
66
commands/ash/bltin/mkexpr
Executable 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
25
commands/ash/bltin/nlecho.c
Executable 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
299
commands/ash/bltin/regexp.c
Executable 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
21
commands/ash/bltin/stalloc.c
Executable 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
19
commands/ash/bltin/umask.c
Executable 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
24
commands/ash/bltin/unary_op
Executable 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
83
commands/ash/builtins.table
Executable 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
372
commands/ash/cd.c
Executable 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
194
commands/ash/dirent.c
Executable 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
252
commands/ash/error.c
Executable 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
116
commands/ash/error.h
Executable 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
926
commands/ash/eval.c
Executable 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
65
commands/ash/eval.h
Executable 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
824
commands/ash/exec.c
Executable 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
75
commands/ash/exec.h
Executable 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
1156
commands/ash/expand.c
Executable file
File diff suppressed because it is too large
Load diff
63
commands/ash/expand.h
Executable file
63
commands/ash/expand.h
Executable 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
49
commands/ash/funcs/cmv
Executable 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
73
commands/ash/funcs/dirs
Executable 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
49
commands/ash/funcs/kill
Executable 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
38
commands/ash/funcs/login
Executable 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
37
commands/ash/funcs/newgrp
Executable 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
73
commands/ash/funcs/popd
Executable 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
Loading…
Reference in a new issue