xzip/0040700000076400007640000000000007173503317010546 5ustar zarfzarfxzip/Makefile0100600000076400007640000001132607173467416012221 0ustar zarfzarfPROGRAM = xzip # You MUST define either BIG_END_MODE or LITTLE_END_MODE, by # uncommenting one of the lines below. If you don't know # which is right, try one and see if the program runs right. # The error messages are nice and obvious. Some Unixes # have a BYTE_ORDER definition; if you define AUTO_END_MODE, # the source code will check for that and work "automatically". # If Murphy's Law strikes, go back to BIG_END_MODE or # LITTLE_END_MODE. # If you get errors in xio.c about fd_set or FD_SET being # undefined, put "-DNEEDS_SELECT_H" in the SYSTEMFLAGS line, # as has been done for the RS6000. # If you get errors about bcopy being undefined, put # "-DNO_BCOPY" in the SYSTEMFLAGS line. # If you get errors about random or srandom being undefined, # put "-DLOUSY_RANDOM" in the SYSTEMFLAGS line. # -------------------- # definitions for RS6000 / AIX # If AUTO doesn't work, use BIG #SYSTEMFLAGS = -DNEEDS_SELECT_H -DAUTO_END_MODE # definitions for HP / HPUX #SYSTEMFLAGS = -Ae -DBIG_END_MODE # definitions for HP / HPUX 9.0 # (Dunno; this was contributed to me) #SYSTEMFLAGS = -Aa -D_HPUX_SOURCE -DBIG_END_MODE # definitions for SparcStation / SunOS #SYSTEMFLAGS = -DBIG_END_MODE # definitions for SparcStation / Solaris # (Solaris 2.5, don't know about other versions) #SYSTEMFLAGS = -DBIG_END_MODE #SYSTEMLIBS = -R$(XLIB) -lsocket # definitions for DECstation / Ultrix #SYSTEMFLAGS = -DLITTLE_END_MODE # definitions for SGI / Irix #SYSTEMFLAGS = -DBIG_END_MODE # definitions for Linux # Note! Old versions of Linux (pre 2.0?) may not have the magic # BYTE_ORDER definitions installed. If AUTO_END_MODE doesn't # work, use LITTLE_END_MODE on an x86, BIG_END_MODE on a # 680x0 or PPC machine. #SYSTEMFLAGS = -DAUTO_END_MODE # definitions for BSDI 4 #SYSTEMFLAGS = -DAUTO_END_MODE # definitions for some arbitrary big-endian system #SYSTEMFLAGS = -DBIG_END_MODE # definitions for some arbitrary little-endian system #SYSTEMFLAGS = -DLITTLE_END_MODE # -------------------- # definitions for where the X lib and include directories are. # The following are defaults that might work. XINCLUDE = /usr/include/X11 XLIB = /usr/lib/X11 # If your compiler can't find these things, try commenting out the # above, and uncommenting various versions below. Also look around # your hard drive for the appropriate files. (The XINCLUDE directory # should contain the file "Xlib.h", and the XLIB dir should contain # "libX11.so" or "libX11.a".) # The problem is, depending on how things are installed, the # directories could be just about anywhere. Sigh. # for Debian or SuSE Linux #XINCLUDE = /usr/X11R6/include/X11 #XLIB = /usr/X11R6/lib # for Red Hat Linux #XINCLUDE = /usr/include/X11 #XLIB = /usr/X11/lib # for SparcStation / Solaris #XINCLUDE = /usr/openwin/include #XLIB = /usr/openwin/lib # for BSDI 4 #XINCLUDE = /usr/X11R6/include #XLIB = /usr/X11/lib # -------------------- # definition for where to install xzip executable and man page DESTDIR = /usr/local # -------------------- CFLAGS = -O $(SYSTEMFLAGS) -I$(XINCLUDE) LDFLAGS = LIBS = -L$(XLIB) -lX11 $(SYSTEMLIBS) # definitions for the default fonts. Users can override these with X resources. FONTDEF_PLAIN=\ "-adobe-times-medium-r-normal--14-*-*-*-*-*-iso8859-1" FONTDEF_BOLD=\ "-adobe-times-bold-r-normal--14-*-*-*-*-*-iso8859-1" FONTDEF_ITALIC=\ "-adobe-times-medium-i-normal--14-*-*-*-*-*-iso8859-1" FONTDEF_BOLDITALIC=\ "-adobe-times-bold-i-normal--14-*-*-*-*-*-iso8859-1" FONTDEF_FIXED=\ "-adobe-courier-medium-r-normal--12-*-*-*-*-*-iso8859-1" FONTDEF_BOLDFIXED=\ "-adobe-courier-bold-r-normal--12-*-*-*-*-*-iso8859-1" FONTDEF_ITALICFIXED=\ "-adobe-courier-medium-o-normal--12-*-*-*-*-*-iso8859-1" FONTDEF_BOLDITALICFIXED=\ "-adobe-courier-bold-o-normal--12-*-*-*-*-*-iso8859-1" FONTDEFAULTLIST = \ -DFND0='$(FONTDEF_PLAIN)' \ -DFND1='$(FONTDEF_BOLD)' \ -DFND2='$(FONTDEF_ITALIC)' \ -DFND3='$(FONTDEF_BOLDITALIC)' \ -DFND4='$(FONTDEF_FIXED)' \ -DFND5='$(FONTDEF_BOLDFIXED)' \ -DFND6='$(FONTDEF_ITALICFIXED)' \ -DFND7='$(FONTDEF_BOLDITALICFIXED)' INC = ztypes.h OBJS = zip.o control.o extern.o fileio.o input.o interpre.o math.o memory.o \ object.o operand.o osdepend.o property.o screen.o text.o variable.o \ pickle.o quetzal.o XOBJS = xio.o xinit.o xtext.o xkey.o xmess.o xstat.o $(PROGRAM) : $(OBJS) $(XOBJS) $(CC) -o $@ $(LDFLAGS) $(OBJS) $(XOBJS) $(LIBS) test: $(XOBJS) $(CC) -o $@ $(LDFLAGS) $(XOBJS) $(LIBS) $(OBJS) : $(INC) extern.c version.h pickle.o : pickle.h $(XOBJS) : $(INC) xio.h version.h xio.o: xio.c xio.h greypm.bm $(CC) $(CFLAGS) -c xio.c xinit.o: xinit.c xio.h $(CC) $(CFLAGS) $(FONTDEFAULTLIST) -c xinit.c install: $(PROGRAM) install -s $(PROGRAM) $(DESTDIR)/bin install $(PROGRAM).1 $(DESTDIR)/man/man1 clean : -rm -f *~ *.o $(PROGRAM) test xzip/arguments.h0100600000076400007640000000152007173477340012727 0ustar zarfzarf typedef struct optionname_t { char *name; int key; int canonical; } optionname; typedef struct unixoption_t { char *name; char *val; } unixoption; #define OPT_HELP (-1) #define OPT_BINDINGS 0 #define OPT_GEOMETRY 1 #define OPT_STATGEOMETRY 2 #define OPT_INPUTSTYLE 3 #define OPT_MARGINX 4 #define OPT_MARGINY 5 #define OPT_LEADING 6 #define OPT_JUSTIFY 7 #define OPT_AUTORESIZE 8 #define OPT_RESIZEUPWARD 15 #define OPT_AUTOCLEAR 9 #define OPT_HISTORY 10 #define OPT_BUFFER 11 #define OPT_BACKGROUND 12 #define OPT_FOREGROUND 13 #define OPT_GREYCOLOR 14 #define OPT_STRICTZ 16 #define OPT_SPEC 17 #define NUM_SIMPLE_OPTIONS 18 #define OPT_STYLECOLOR (NUM_SIMPLE_OPTIONS) #define OPT_STYLEFONT (NUM_SIMPLE_OPTIONS+NUMFONTS) #define NUMOPTIONS (NUM_SIMPLE_OPTIONS+2*NUMFONTS) extern unixoption unixoptionlist[NUMOPTIONS]; xzip/control.c0100600000076400007640000001551707173500244012376 0ustar zarfzarf/* * control.c * * Functions that alter the flow of control. * */ #include "ztypes.h" static const char *v1_lookup_table[3] = { "abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", " 0123456789.,!?_#'\"/\\<-:()" }; static const char *v3_lookup_table[3] = { "abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", " \n0123456789.,!?_#'\"/\\-:()" }; /* * check_argument * * Jump if argument is present. * */ #ifdef __STDC__ void check_argument (zword_t argc) #else void check_argument (argc) zword_t argc; #endif { conditional_jump (argc <= (zword_t) (stack[fp + 1] & ARGS_MASK)); }/* check_argument */ /* * call * * Call a subroutine. Save PC and FP then load new PC and initialise stack based * local arguments. * */ #ifdef __STDC__ int call (int argc, zword_t *argv, int type) #else int call (argc, argv, type) int argc; zword_t *argv; int type; #endif { zword_t arg; int i = 1, args, status = 0; /* Convert calls to 0 as returning FALSE */ if (argv[0] == 0) { if (type == FUNCTION) store_operand (FALSE); return (0); } /* Save current PC, FP and argument count on stack */ stack[--sp] = (zword_t) (pc / PAGE_SIZE); stack[--sp] = (zword_t) (pc % PAGE_SIZE); stack[--sp] = fp; stack[--sp] = (argc - 1) | type; /* Create FP for new subroutine and load new PC */ fp = sp - 1; pc = (unsigned long) argv[0] * story_scaler; ++frame_count; /* Read argument count and initialise local variables */ args = (unsigned int) read_code_byte (); stack[sp] |= args << VAR_SHIFT; while (--args >= 0) { arg = (h_type > V4) ? 0 : read_code_word (); stack[--sp] = (--argc > 0) ? argv[i++] : arg; } /* If the call is asynchronous then call the interpreter directly. We will return back here when the corresponding return frame is encountered in the ret call. */ if (type == ASYNC) { status = interpret (); interpreter_state = RUN; interpreter_status = 1; } return (status); }/* call */ /* * ret * * Return from subroutine. Restore FP and PC from stack. * */ #ifdef __STDC__ void ret (zword_t value) #else void ret (value) zword_t value; #endif { zword_t argc; /* Clean stack */ sp = fp + 1; /* Restore argument count, FP and PC */ argc = stack[sp++]; fp = stack[sp++]; pc = stack[sp++]; pc += (unsigned long) stack[sp++] * PAGE_SIZE; --frame_count; /* If this was an async call then stop the interpreter and return the value from the async routine. This is slightly hacky using a global state variable, but ret can be called with conditional_jump which in turn can be called from all over the place, sigh. A better design would have all opcodes returning the status RUN, but this is too much work and makes the interpreter loop look ugly */ if ((argc & TYPE_MASK) == ASYNC) { interpreter_state = STOP; interpreter_status = (int) value; } else { /* Return subroutine value for function call only */ if ((argc & TYPE_MASK) == FUNCTION) store_operand (value); } }/* ret */ /* * jump * * Unconditional jump. Jump is PC relative. * */ #ifdef __STDC__ void jump (zword_t offset) #else void jump (offset) zword_t offset; #endif { pc = (unsigned long) (pc + (short) offset - 2); }/* jump */ /* * restart * * Restart game by initialising environment and reloading start PC. * */ #ifdef __STDC__ void restart (void) #else void restart () #endif { unsigned int i, j, restart_size, scripting_flag; /* Reset output buffer */ flush_buffer (TRUE); /* Reset text control flags */ formatting = ON; outputting = ON; redirect_depth = 0; scripting_disable = OFF; /* Randomise */ SRANDOM_FUNC ((unsigned int) time (NULL)); /* Remember scripting state */ scripting_flag = get_word (H_FLAGS) & SCRIPTING_FLAG; /* Load restart size and reload writeable data area */ restart_size = (h_restart_size / PAGE_SIZE) + 1; for (i = 0; i < restart_size; i++) read_page (i, &datap[i * PAGE_SIZE]); /* Restart the screen */ set_status_size (0); set_attribute (NORMAL); erase_window (SCREEN); restart_screen (); /* Reset the interpreter state */ restart_interp (scripting_flag); /* Initialise the character translation lookup tables */ for (i = 0; i < 3; i++) { for (j = 0; j < 26; j++) { if (h_alternate_alphabet_offset) { lookup_table[i][j] = get_byte (h_alternate_alphabet_offset + (i * 26) + j); } else { if (h_type == V1) lookup_table[i][j] = v1_lookup_table[i][j]; else lookup_table[i][j] = v3_lookup_table[i][j]; } } } /* Load start PC, SP and FP */ pc = h_start_pc; sp = STACK_SIZE; fp = STACK_SIZE - 1; frame_count = 0; }/* restart */ /* * restart_interp * * Do all the things which need to be done after startup, restart, and restore * commands. * */ #ifdef __STDC__ void restart_interp (int scripton_flag) #else void restart_interp (scripton_flag) int scripton_flag; #endif { if (scripton_flag) set_word (H_FLAGS, (get_word (H_FLAGS) | SCRIPTING_FLAG)); set_byte (H_INTERPRETER, h_interpreter); set_byte (H_INTERPRETER_VERSION, h_interpreter_version); if (strictz_declare_spec) { set_byte (0x32, 0x01); set_byte (0x33, 0x00); } set_byte (H_SCREEN_ROWS, screen_rows); /* Screen dimension in characters */ set_byte (H_SCREEN_COLUMNS, screen_cols); set_byte (H_SCREEN_LEFT, 0); /* Screen dimension in smallest addressable units, ie. pixels */ set_byte (H_SCREEN_RIGHT, screen_cols); set_byte (H_SCREEN_TOP, 0); set_byte (H_SCREEN_BOTTOM, screen_rows); set_byte (H_MAX_CHAR_WIDTH, 1); /* Size of a character in screen units */ set_byte (H_MAX_CHAR_HEIGHT, 1); /* Initialise status region */ if (h_type < V4) { set_status_size (0); blank_status_line (); } }/* restart_interp */ /* * get_fp * * Return the value of the frame pointer (FP) for later use with unwind. * Before V5 games this was a simple pop. * */ #ifdef __STDC__ void get_fp (void) #else void get_fp () #endif { if (h_type > V4) store_operand (frame_count); else sp++; }/* get_fp */ /* * unwind * * Remove one or more stack frames and return. Works like longjmp, see get_fp. * */ #ifdef __STDC__ void unwind (zword_t value, zword_t new_fp) #else void unwind (value, new_fp) zword_t value; zword_t new_fp; #endif { if (new_fp > frame_count) fatal ("Bad frame for unwind"); for (; new_fp < frame_count; --frame_count) { sp = fp + 1; fp = stack[sp+1]; } ret (value); }/* unwind */ xzip/extern.c0100600000076400007640000000323706551763103012223 0ustar zarfzarf/* * extern.c * * Global data. * */ #include "ztypes.h" /* Game header data */ zbyte_t h_type = 0; zbyte_t h_config = 0; zword_t h_version = 0; zword_t h_data_size = 0; zword_t h_start_pc = 0; zword_t h_words_offset = 0; zword_t h_objects_offset = 0; zword_t h_globals_offset = 0; zword_t h_restart_size = 0; zword_t h_flags = 0; zword_t h_synonyms_offset = 0; zword_t h_file_size = 0; zword_t h_checksum = 0; zbyte_t h_interpreter = INTERP_MSDOS; zbyte_t h_interpreter_version = 'B'; /* Interpreter version 2 */ zword_t h_alternate_alphabet_offset = 0; /* Game version specific data */ int story_scaler = 0; int story_shift = 0; int property_mask = 0; int property_size_mask = 0; /* Stack and PC data */ zword_t stack[STACK_SIZE]; zword_t sp = STACK_SIZE; zword_t fp = STACK_SIZE - 1; zword_t frame_count = 0; /* frame pointer for get_fp */ unsigned long pc = 0; int interpreter_state = RUN; int interpreter_status = 0; /* Data region data */ unsigned int data_size = 0; zbyte_t *datap = NULL; zbyte_t *undo_datap = NULL; /* Screen size data */ int screen_rows = 0; int screen_cols = 0; /* Current window data */ int screen_window = TEXT_WINDOW; /* Formatting and output control data */ int formatting = ON; int outputting = ON; int redirect_depth = 0; /* 1 or higher means ON */ int scripting_disable = OFF; int scripting = OFF; int recording = OFF; int replaying = OFF; int font = 1; /* Status region data */ int status_active = OFF; int status_size = 0; /* Text output buffer data */ int lines_written = 0; int status_pos = 0; /* Dynamic buffer data */ /*char *line = NULL;*/ char *status_line = NULL; /* Character translation tables */ char lookup_table[3][26]; xzip/fileio.c0100600000076400007640000007034506706745024012175 0ustar zarfzarf/* * fileio.c * * File manipulation routines. Should be generic. * */ #include "ztypes.h" #include "pickle.h" /* A couple of definitions for constants used to access PICKLE files. Both are Mac-style four-byte constants. You can read each as four characters, MSB first. (Don't worry about whether your system is big- or little-endian; the PICKLE library takes care of that stuff.) */ /* The "use" of executable chunks */ #define PICKLETYPE_exec (0x65786563) /* The "format" of executable chunks containing Z-code */ #define PICKLETYPE_zcod (0x7a636f64) /* All of the following variables are set in open_story(). */ /* is_pickle is a boolean flag; it will be TRUE if the open zcode is contained in a PICKLE file. It is not static because other modules may wish to check its value. */ int is_pickle; /* pickle_map is the opaque handle to the PICKLE file map in memory. It is not static because other modules will need it in order to load PICKLE chunks. */ pikMapPtr pickle_map; /* zcode_length is the length of the zcode. If is_pickle is FALSE, this is the actual file length. */ static unsigned long zcode_length; /* zcode_offset is the starting position of the zcode in its file. If is_pickle is FALSE, this is just 0. */ static unsigned long zcode_offset; /* Static data */ static FILE *gfp = NULL; /* Game file pointer */ static FILE *sfp = NULL; /* Script file pointer */ static FILE *rfp = NULL; /* Record file pointer */ static char save_name[FILENAME_MAX + 1] = ""; static char savedata_name[FILENAME_MAX + 1] = ""; static char script_name[FILENAME_MAX + 1] = ""; static char record_name[FILENAME_MAX + 1] = ""; static int undo_valid = FALSE; static zword_t undo_stack[STACK_SIZE]; static int script_file_valid = FALSE; #ifdef __STDC__ static int save_restore (const char *, int); static int save_restore_data (const char *, int, int, zword_t *); static void set_names (const char *); static void swap_bytes (zword_t *, int); #else static int save_restore (); static int save_restore_data (); static void set_names (); static void swap_bytes (); #endif /* * set_names * * Set up the story names intelligently. * Taken from JZip, John Holder, 28 Sept 1995 */ #ifdef __STDC__ static void set_names (const char *storyname) #else static void set_names (storyname) const char *storyname; #endif { char *per_pos=0; /* experimental setting of save_name, added by John Holder 26 July 1995 */ per_pos = strrchr(storyname,'.'); /* find last '.' in storyname. */ if (per_pos) /* The story file looks like "Odius.dat" or "odieus.z3" */ { strcpy(save_name, storyname); per_pos=strrchr(save_name,'.'); *(per_pos) = '\0'; strcat(save_name,".sav"); strcpy(script_name, storyname); per_pos=strrchr(script_name,'.'); *(per_pos) = '\0'; strcat(script_name,".scr"); strcpy(savedata_name, storyname); per_pos=strrchr(savedata_name,'.'); *(per_pos) = '\0'; strcat(savedata_name,".dat"); strcpy(record_name, storyname); per_pos=strrchr(record_name,'.'); *(per_pos) = '\0'; strcat(record_name,".rec"); } else /* The story file looks like: "OdieusQuest" */ { strcpy(save_name, storyname); strcat(save_name,".sav"); strcpy(script_name, storyname); strcat(script_name,".scr"); strcpy(savedata_name, storyname); strcat(savedata_name,".dat"); strcpy(record_name, storyname); strcat(record_name,".rec"); } } /* set_names */ /* * open_story * * Open game file for read. * */ #ifdef __STDC__ void open_story (const char *storyname) #else void open_story (storyname) const char *storyname; #endif { /* Most of this function is new. --Z */ int ix; char firstfour[4]; pikErr err; pikChunkID chunkid; pikChunk chunk; /* This is the list of formats that the PICKLE library will check for. You can extend it in the obvious way. */ #define NUMPICKLEFORMATS (4) static pikFormat formatlist[NUMPICKLEFORMATS] = { {PICKLETYPE_zcod, 3}, {PICKLETYPE_zcod, 4}, {PICKLETYPE_zcod, 5}, {PICKLETYPE_zcod, 8} }; /* The following three lines are what used to here. --Z */ gfp = fopen (storyname, "rb"); if (gfp == NULL && storyname[0] != '/') { /* Try the magic path variable. */ char *classpath = getenv("INFOCOM_PATH"); if (classpath && strlen(classpath) > 0) { char *p; p = strtok(classpath, ":"); while (p && !gfp) { char classfile[FILENAME_MAX+1]; sprintf(classfile, "%s/%s", p, storyname); gfp = fopen (classfile, "rb"); p = strtok(NULL, ":"); } } } if (gfp == NULL) fatal ("Game file not found"); set_names(storyname); /* Now the new code... --Z */ for (ix = 0; ix < 4; ix++) { firstfour[ix] = fgetc (gfp); if (firstfour[ix] == EOF) break; } /* The PICKLE library doesn't require the file to be rewound here, and standard ZIP doesn't either, but it doesn't hurt to be sure. */ rewind(gfp); is_pickle = FALSE; zcode_length = 0; zcode_offset = 0; if (ix == 4) { if (pikIsPickleHeader(firstfour)) { /* Yes! It is indeed a PICKLE file! */ is_pickle = TRUE; /* Open the PICKLE file and load the map into memory. */ err = pikCreateMap(gfp, &pickle_map); if (err) fatal ("Unable to open PICKLE file"); /* Find and load the Z-code chunk. */ err = pikFindChunk(pickle_map, PICKLETYPE_exec, 0, NUMPICKLEFORMATS, formatlist, &chunkid); if (err == pikerr_NotFound) fatal ("There is no Z-code chunk in this PICKLE file"); if (err) fatal ("Unable to search PICKLE file"); err = pikLoadChunk(pickle_map, chunkid, pikmethod_FilePos, &chunk); if (err) fatal ("Unable to read Z-code chunk from PICKLE file"); zcode_offset = chunk.data.startpos; zcode_length = chunk.length; } } }/* open_story */ /* * close_story * * Close game file if open. * */ #ifdef __STDC__ void close_story (void) #else void close_story () #endif { if (is_pickle) { /* --Z */ pikDestroyMap(pickle_map); } /* --Z */ /* The rest of this function is not changed. --Z */ if (gfp != NULL) fclose (gfp); }/* close_story */ /* * get_story_size * * Calculate the size of the game file. Only used for very old games that do not * have the game file size in the header. * */ #ifdef __STDC__ unsigned int get_story_size (void) #else unsigned int get_story_size () #endif { unsigned long file_length; if (!is_pickle) { /* --Z */ /* Read whole file to calculate file size */ rewind (gfp); for (file_length = 0; fgetc (gfp) != EOF; file_length++) ; rewind (gfp); } else { /* Use the length loaded from the PICKLE file */ file_length = zcode_length; } /* --Z */ /* The rest of this function is not changed. --Z */ /* Calculate length of file in game allocation units */ file_length = (file_length + (unsigned long) (story_scaler - 1)) / (unsigned long) story_scaler; return ((unsigned int) file_length); }/* get_story_size */ /* * read_page * * Read one game file page. * */ #ifdef __STDC__ void read_page (int page, void *buffer) #else void read_page (page, buffer) int page; void *buffer; #endif { unsigned long file_size; unsigned int pages, offset; /* Seek to start of page */ fseek (gfp, zcode_offset + (long) page * PAGE_SIZE, SEEK_SET); /* Read the page */ if (fread (buffer, PAGE_SIZE, 1, gfp) != 1) { /* Read failed. Are we in the last page? */ file_size = (unsigned long) h_file_size * story_scaler; pages = (unsigned int) ((unsigned long) file_size / PAGE_SIZE); offset = (unsigned int) ((unsigned long) file_size & PAGE_MASK); if ((unsigned int) page == pages) { /* Read partial page if this is the last page in the game file */ fseek (gfp, zcode_offset + (long) page * PAGE_SIZE, SEEK_SET); if (fread (buffer, offset, 1, gfp) == 1) return; } fatal ("Game file read error"); } }/* read_page */ /* * verify * * Verify game ($verify verb). Add all bytes in game file except for bytes in * the game file header. * */ #ifdef __STDC__ void verify (void) #else void verify () #endif { unsigned long file_size; unsigned int pages, offset; unsigned int start, end, i, j; zword_t checksum = 0; zbyte_t buffer[PAGE_SIZE]; /* Print version banner */ if (h_type < V4) { write_string ("ZIP Interpreter "); print_number (get_byte (H_INTERPRETER)); write_string (", Version "); write_char (get_byte (H_INTERPRETER_VERSION)); write_string ("."); new_line (); } /* Calculate game file dimensions */ file_size = (unsigned long) h_file_size * story_scaler; pages = (unsigned int) ((unsigned long) file_size / PAGE_SIZE); offset = (unsigned int) file_size & PAGE_MASK; /* Sum all bytes in game file, except header bytes */ for (i = 0; i <= pages; i++) { read_page (i, buffer); start = (i == 0) ? 64 : 0; end = (i == pages) ? offset : PAGE_SIZE; for (j = start; j < end; j++) checksum += buffer[j]; } /* Make a conditional jump based on whether the checksum is equal */ conditional_jump (checksum == h_checksum); }/* verify */ /* * save * * Save game state to disk. Returns: * 0 = save failed * 1 = save succeeded * */ #ifdef __STDC__ int save (int argc, zword_t *argv) #else int save (argc, argv) int argc; zword_t *argv; #endif { int status = 1; /* assume failure */ int storestatus = 0; if (argc == 0) { char new_save_name[FILENAME_MAX + 1]; /* Get the file name */ if (get_file_name (new_save_name, save_name, GAME_SAVE) == 0) { /* Do a save operation */ if (save_restore (new_save_name, GAME_SAVE) == 0) { /* Cleanup file */ file_cleanup (new_save_name, GAME_SAVE); /* Save the new name as the default file name */ strcpy (save_name, new_save_name); /* Indicate success */ status = 0; } } storestatus = ((status == 0) ? 1 : 0); } else { char new_savedata_name[FILENAME_MAX + 1]; char defname[FILENAME_MAX + 1]; char *defnameptr = NULL; if (argc >= 3) { unsigned char *cx = datap + argv[2]; int cxlen = cx[0]; memcpy(defname, cx+1, cxlen); defname[cxlen] = '\0'; defnameptr = defname; } /* Get the file name ### defname */ if (get_file_name (new_savedata_name, savedata_name, GAME_SAVEDATA) == 0) { /* Do a save operation */ storestatus = save_restore_data (new_savedata_name, GAME_SAVEDATA, argc, argv); if (storestatus != 0) { /* Cleanup file */ file_cleanup (new_savedata_name, GAME_SAVEDATA); /* Save the new name as the default file name */ strcpy (savedata_name, new_savedata_name); /* Indicate success */ status = 0; } } } /* Return result of save to Z-code */ if (h_type < V4) conditional_jump (status == 0); else store_operand (storestatus); return (status); }/* save */ /* * restore * * Restore game state from disk. Returns: * 0 = restore failed * 2 = restore succeeded * */ #ifdef __STDC__ int restore (int argc, zword_t *argv) #else int restore (argc, argv) int argc; zword_t *argv; #endif { int status = 1; /* assume failure */ int storestatus = 0; if (argc == 0) { char new_save_name[FILENAME_MAX + 1]; /* Get the file name */ if (get_file_name (new_save_name, save_name, GAME_RESTORE) == 0) { /* Do the restore operation */ if (save_restore (new_save_name, GAME_RESTORE) == 0) { /* Cleanup file */ file_cleanup (new_save_name, GAME_SAVE); /* Save the new name as the default file name */ strcpy (save_name, new_save_name); /* Indicate success */ status = 0; } } storestatus = ((status == 0) ? 2 : 0); } else { char new_savedata_name[FILENAME_MAX + 1]; char defname[FILENAME_MAX + 1]; char *defnameptr = NULL; if (argc >= 3) { unsigned char *cx = datap + argv[2]; int cxlen = cx[0]; memcpy(defname, cx+1, cxlen); defname[cxlen] = '\0'; defnameptr = defname; } /* Get the file name ### defname */ if (get_file_name (new_savedata_name, savedata_name, GAME_RESTOREDATA) == 0) { /* Do the restore operation */ storestatus = save_restore_data (new_savedata_name, GAME_RESTOREDATA, argc, argv); if (storestatus != 0) { /* Cleanup file */ file_cleanup (new_savedata_name, GAME_RESTOREDATA); /* Save the new name as the default file name */ strcpy (savedata_name, new_savedata_name); /* Indicate success */ status = 0; } } } /* Return result of save to Z-code */ if (h_type < V4) conditional_jump (status == 0); else store_operand (storestatus); return (status); }/* restore */ /* * undo_save * * Save the current Z machine state in memory for a future undo. Returns: * -1 = feature unavailable * 0 = save failed * 1 = save succeeded * */ #ifdef __STDC__ void undo_save (void) #else void undo_save () #endif { /* Check if undo is available first */ if (undo_datap != NULL) { /* Save the undo data and return success */ save_restore (NULL, UNDO_SAVE); undo_valid = TRUE; store_operand (1); } else /* If no memory for data area then say undo is not available */ store_operand ((zword_t) -1); }/* undo_save */ /* * undo_restore * * Restore the current Z machine state from memory. Returns: * -1 = feature unavailable * 0 = restore failed * 2 = restore succeeded * */ #ifdef __STDC__ void undo_restore (void) #else void undo_restore () #endif { /* Check if undo is available first */ if (undo_datap != NULL) { /* If no undo save done then return an error */ if (undo_valid == TRUE) { /* Restore the undo data and return success */ save_restore (NULL, UNDO_RESTORE); store_operand (2); } else store_operand (0); } else /* If no memory for data area then say undo is not available */ store_operand ((zword_t) -1); }/* undo_restore */ /* * swap_bytes * * Swap the low and high bytes in every word of the specified array. * The length is specified in BYTES! * * This routine added by Mark Phillips(msp@bnr.co.uk), Thanks Mark! */ #ifdef __STDC__ static void swap_bytes(zword_t *ptr, int len) #else static void swap_bytes(ptr, len) zword_t *ptr; int len; #endif { unsigned char *pbyte; unsigned char tmp; len/=2; /* convert len into number of 2 byte words */ pbyte=(unsigned char*)ptr; while (len) { tmp=pbyte[0]; pbyte[0]=pbyte[1]; pbyte[1]=tmp; pbyte+=2; len--; } return; } /* * save_restore * * Common save and restore code. Just save or restore the game stack and the * writeable data area. * */ #ifdef __STDC__ static int save_restore (const char *file_name, int flag) #else static int save_restore (file_name, flag) const char *file_name; int flag; #endif { FILE *tfp = NULL; int scripting_flag = 0, status = 0; #ifdef BIG_END_MODE int little_endian=0; #else int little_endian=1; #endif /* Open the save file and disable scripting */ if (flag == GAME_SAVE || flag == GAME_RESTORE) { if ((tfp = fopen (file_name, (flag == GAME_SAVE) ? "wb" : "rb")) == NULL) { output_line ("Cannot open SAVE file"); return (1); } scripting_flag = get_word (H_FLAGS) & SCRIPTING_FLAG; set_word (H_FLAGS, get_word (H_FLAGS) & (~SCRIPTING_FLAG)); } #if defined(USE_QUETZAL) if (flag == GAME_SAVE) status = !save_quetzal (tfp, gfp, zcode_offset); else if (flag == GAME_RESTORE) status = !restore_quetzal (tfp, gfp, zcode_offset); else { #endif /* defined(USE_QUETZAL) */ /* Push PC, FP, version and store SP in special location */ stack[--sp] = (zword_t) (pc / PAGE_SIZE); stack[--sp] = (zword_t) (pc % PAGE_SIZE); stack[--sp] = fp; stack[--sp] = h_version; stack[0] = sp; /* Save or restore stack */ #if !defined(USE_QUETZAL) if (flag == GAME_SAVE) { if (little_endian) swap_bytes(stack, sizeof(stack)); if (status == 0 && fwrite (stack, sizeof (stack), 1, tfp) != 1) status = 1; if (little_endian) swap_bytes(stack, sizeof(stack)); } else if (flag == GAME_RESTORE) { if (little_endian) swap_bytes(stack, sizeof(stack)); if (status == 0 && fread (stack, sizeof (stack), 1, tfp) != 1) status = 1; if (little_endian) swap_bytes(stack, sizeof(stack)); } else #endif/* !defined(USE_QUETZAL) */ if (flag == UNDO_SAVE) { memmove (undo_stack, stack, sizeof (stack)); } else /* if (flag == UNDO_RESTORE) */ memmove (stack, undo_stack, sizeof (stack)); /* Restore SP, check version, restore FP and PC */ sp = stack[0]; if (stack[sp++] != h_version) fatal ("Wrong game or version"); fp = stack[sp++]; pc = stack[sp++]; pc += (unsigned long) stack[sp++] * PAGE_SIZE; /* Save or restore writeable game data area */ #if !defined(USE_QUETZAL) if (flag == GAME_SAVE) { if (status == 0 && fwrite (datap, h_restart_size, 1, tfp) != 1) status = 1; } else if (flag == GAME_RESTORE) { if (status == 0 && fread (datap, h_restart_size, 1, tfp) != 1) status = 1; } else #endif /* !defined(USE_QUETZAL) */ if (flag == UNDO_SAVE) { memmove (undo_datap, datap, h_restart_size); } else /* if (flag == UNDO_RESTORE) */ memmove (datap, undo_datap, h_restart_size); #if defined(USE_QUETZAL) } #endif /* defined(USE_QUETZAL) */ /* Close the save file and restore scripting */ if (flag == GAME_SAVE) { fclose (tfp); if (scripting_flag) set_word (H_FLAGS, get_word (H_FLAGS) | SCRIPTING_FLAG); } else if (flag == GAME_RESTORE) { fclose (tfp); restart_screen(); restart_interp(scripting_flag); } /* Handle read or write errors */ if (status) { if (flag == GAME_SAVE) { output_line ("Write to SAVE file failed"); remove (file_name); } else { output_line ("Read from SAVE file failed"); } } return (status); }/* save_restore */ /* * open_script * * Open the scripting file. * */ #ifdef __STDC__ void open_script (void) #else void open_script () #endif { char new_script_name[FILENAME_MAX + 1]; /* Open scripting file if closed */ if (scripting == OFF) { if (script_file_valid == TRUE) { sfp = fopen (script_name, "a"); /* Turn on scripting if open succeeded */ if (sfp != NULL) scripting = ON; else output_line ("Script file open failed"); } else { /* Get scripting file name and record it */ if (get_file_name (new_script_name, script_name, GAME_SCRIPT) == 0) { /* Open scripting file */ sfp = fopen (new_script_name, "w"); /* Turn on scripting if open succeeded */ if (sfp != NULL) { script_file_valid = TRUE; /* Make file name the default name */ strcpy (script_name, new_script_name); /* Turn on scripting */ scripting = ON; } else output_line ("Script file create failed"); } } } /* Set the scripting flag in the game file flags */ if (datap) { if (scripting == ON) set_word (H_FLAGS, get_word (H_FLAGS) | SCRIPTING_FLAG); else set_word (H_FLAGS, get_word (H_FLAGS) & (~SCRIPTING_FLAG)); } }/* open_script */ /* * close_script * * Close the scripting file. * */ #ifdef __STDC__ void close_script (void) #else void close_script () #endif { /* Close scripting file if open */ if (scripting == ON) { fclose (sfp); #if 0 /* Cleanup */ file_cleanup (script_name, GAME_SCRIPT); #endif /* Turn off scripting */ scripting = OFF; } /* Set the scripting flag in the game file flags */ if (datap) { if (scripting == OFF) set_word (H_FLAGS, get_word (H_FLAGS) & (~SCRIPTING_FLAG)); else set_word (H_FLAGS, get_word (H_FLAGS) | SCRIPTING_FLAG); } }/* close_script */ /* * script_char * * Write one character to scripting file. * * Check the state of the scripting flag first. Older games only set the * scripting flag in the game flags instead of calling the set_print_modes * function. This is because they expect a physically attached printer that * doesn't need opening like a file. */ #ifdef __STDC__ void script_char (int c) #else void script_char (c) int c; #endif { /* Check the state of the scripting flag in the game flags. If it is on then check to see if the scripting file is open as well */ if ((get_word (H_FLAGS) & SCRIPTING_FLAG) != 0 && scripting == OFF) open_script (); /* Check the state of the scripting flag in the game flags. If it is off then check to see if the scripting file is closed as well */ if ((get_word (H_FLAGS) & SCRIPTING_FLAG) == 0 && scripting == ON) close_script (); /* If scripting file is open, we are in the text window and the character is printable then write the character */ if (scripting == ON && scripting_disable == OFF && (c == '\n' || (isprint (c)))) putc (c, sfp); }/* script_char */ /* * script_string * * Write a string to the scripting file. * */ #ifdef __STDC__ void script_string (const char *s) #else void script_string (s) const char *s; #endif { /* Write string */ while (*s) script_char (*s++); }/* script_string */ /* * script_line * * Write a string followed by a new line to the scripting file. * */ #ifdef __STDC__ void script_line (const char *s, int len) #else void script_line (s, len) const char *s; int len; #endif { int ix; /* Write string */ for (ix=0; ix\n", c); } }/* record_key */ /* * close_record * * Turn off recording of all input to an output file. * */ #ifdef __STDC__ void close_record (void) #else void close_record () #endif { /* Close recording file */ if (rfp != NULL) { fclose (rfp); rfp = NULL; /* Cleanup */ if (recording == ON) file_cleanup (record_name, GAME_RECORD); else /* (replaying == ON) */ file_cleanup (record_name, GAME_PLAYBACK); } /* Set recording and replaying off */ recording = OFF; replaying = OFF; }/* close_record */ /* * open_playback * * Take input from command file instead of keyboard. * */ #ifdef __STDC__ void open_playback (int arg) #else void open_playback (arg) int arg; #endif { char new_record_name[FILENAME_MAX + 1]; /* If recording or replaying is already on then complain */ if (recording == ON || replaying == ON) { output_line ("Recording or replaying is already active."); } else { /* Get recording file name */ if (get_file_name (new_record_name, record_name, GAME_PLAYBACK) == 0) { /* Open recording file */ rfp = fopen (new_record_name, "r"); /* Turn on recording if open succeeded */ if (rfp != NULL) { /* Make file name the default name */ strcpy (record_name, new_record_name); /* Set replaying on */ replaying = ON; } else output_line ("Record file open failed"); } } }/* open_playback */ /* * playback_line * * Get a line of input from the command file. * */ #ifdef __STDC__ int playback_line (int buflen, char *buffer, int *read_size) #else int playback_line (buflen, buffer, read_size) int buflen; char *buffer; int *read_size; #endif { char *cp; if (recording == ON || replaying == OFF) return (-1); if (fgets (buffer, buflen, rfp) == NULL) { close_record (); return (-1); } else { cp = strrchr (buffer, '\n'); if (cp != NULL) *cp = '\0'; *read_size = strlen (buffer); output_line (buffer); } return ('\n'); }/* playback_line */ /* * playback_key * * Get a key from the command file. * */ #ifdef __STDC__ int playback_key (void) #else int playback_key () #endif { int c; if (recording == ON || replaying == OFF) return (-1); if (fscanf (rfp, "<%o>\n", &c) == EOF) { close_record (); c = -1; } return (c); }/* playback_key */ /* * save_restore_data. This returns the actual z-machine status: number of bytes * loaded for a restore; 0 for failure / 1 for success, for a save. * */ #ifdef __STDC__ static int save_restore_data (const char *file_name, int flag, int argc, zword_t *argv) #else static int save_restore_data (file_name, flag, argc, argv) const char *file_name; int flag; int argc; zword_t *argv; #endif { FILE *tfp; long dat_begin, dat_len; int status, val; long lx; char *cx; if (argc < 2) return (1); dat_begin = argv[0]; dat_len = argv[1]; /* Open the save file */ if (flag == GAME_SAVEDATA) tfp = fopen (file_name, "wb"); else tfp = fopen (file_name, "rb"); if (tfp == NULL) { output_line ("Cannot open DATA file"); return (1); } /* Save or restore writeable game data area */ if (flag == GAME_SAVEDATA) { lx = fwrite (datap+dat_begin, 1, dat_len, tfp); if (lx != dat_len) { output_line ("Write to DATA file failed"); status = 0; } else { status = 1; } } else if (flag == GAME_RESTOREDATA) { lx = fread (datap+dat_begin, 1, dat_len, tfp); status = lx; /* number of bytes read */ } /* Close the save file */ fclose (tfp); return (status); } /* save_restore_data */ xzip/getopt.c0100600000076400007640000000021106551763103012205 0ustar zarfzarf#include #include /* I don't use getopt() any more, and it's a pain for porting, so I get rid of it. Ha! --zarf */ xzip/greypm.bm0100600000076400007640000000043106551763103012366 0ustar zarfzarf#define greypm_width 16 #define greypm_height 16 static char greypm_bits[] = { 0x11, 0x11, 0x44, 0x44, 0x11, 0x11, 0x44, 0x44, 0x11, 0x11, 0x44, 0x44, 0x11, 0x11, 0x44, 0x44, 0x11, 0x11, 0x44, 0x44, 0x11, 0x11, 0x44, 0x44, 0x11, 0x11, 0x44, 0x44, 0x11, 0x11, 0x44, 0x44}; xzip/interpre.c0100600000076400007640000002264306551763103012550 0ustar zarfzarf/* * interpre.c * * Main interpreter loop * */ #include "ztypes.h" static int halt = FALSE; /* * interpret * * Interpret Z code * */ #ifdef __STDC__ int interpret () #else int interpret () #endif { zbyte_t opcode; zword_t specifier, operand[8]; int maxoperands, count, extended, i; interpreter_status = 1; /* Loop until HALT instruction executed */ for (interpreter_state = RUN; interpreter_state == RUN && halt == FALSE; ) { /* Load opcode and set operand count */ opcode = read_code_byte (); if (h_type > V4 && opcode == 0xbe) { opcode = read_code_byte (); extended = TRUE; } else extended = FALSE; count = 0; /* Multiple operand instructions */ if ((opcode < 0x80 || opcode > 0xc0) || extended == TRUE) { /* Two operand class, load both operands */ if (opcode < 0x80 && extended == FALSE) { operand[count++] = load_operand ((opcode & 0x40) ? 2 : 1); operand[count++] = load_operand ((opcode & 0x20) ? 2 : 1); opcode &= 0x1f; } else { /* Variable operand class, load operand specifier */ opcode &= 0x3f; if (opcode == 0x2c || opcode == 0x3a) { /* Extended CALL instruction */ specifier = read_code_word (); maxoperands = 8; } else { specifier = read_code_byte (); maxoperands = 4; } /* Load operands */ for (i = (maxoperands - 1) * 2; i >= 0; i -= 2) if (((specifier >> i) & 0x03) != 3) operand[count++] = load_operand ((specifier >> i) & 0x03); else i = 0; } if (extended == TRUE) switch ((char) opcode) { /* Extended operand instructions */ case 0x00: save (count, operand); break; case 0x01: restore (count, operand); break; case 0x02: shift (operand[0], operand[1]); break; case 0x03: arith_shift (operand[0], operand[1]); break; case 0x04: set_font_attribute (operand[0]); break; case 0x09: undo_save (); break; case 0x0a: undo_restore (); break; default: fatal ("Illegal operation"); } else switch ((char) opcode) { /* Two or multiple operand instructions */ case 0x01: compare_je (count, operand); break; case 0x02: compare_jl (operand[0], operand[1]); break; case 0x03: compare_jg (operand[0], operand[1]); break; case 0x04: decrement_check (operand[0], operand[1]); break; case 0x05: increment_check (operand[0], operand[1]); break; case 0x06: compare_parent_object (operand[0], operand[1]); break; case 0x07: test (operand[0], operand[1]); break; case 0x08: or (operand[0], operand[1]); break; case 0x09: and (operand[0], operand[1]); break; case 0x0a: test_attr (operand[0], operand[1]); break; case 0x0b: set_attr (operand[0], operand[1]); break; case 0x0c: clear_attr (operand[0], operand[1]); break; case 0x0d: store_variable (operand[0], operand[1]); break; case 0x0e: insert_object (operand[0], operand[1]); break; case 0x0f: load_word (operand[0], operand[1]); break; case 0x10: load_byte (operand[0], operand[1]); break; case 0x11: load_property (operand[0], operand[1]); break; case 0x12: load_property_address (operand[0], operand[1]); break; case 0x13: load_next_property (operand[0], operand[1]); break; case 0x14: add (operand[0], operand[1]); break; case 0x15: subtract (operand[0], operand[1]); break; case 0x16: multiply (operand[0], operand[1]); break; case 0x17: divide (operand[0], operand[1]); break; case 0x18: remainder (operand[0], operand[1]); break; case 0x19: call (count, operand, FUNCTION); break; case 0x1a: call (count, operand, PROCEDURE); break; case 0x1b: set_colour_attribute (operand[0], operand[1]); break; case 0x1c: unwind (operand[0], operand[1]); break; /* Multiple operand instructions */ case 0x20: call (count, operand, FUNCTION); break; case 0x21: store_word (operand[0], operand[1], operand[2]); break; case 0x22: store_byte (operand[0], operand[1], operand[2]); break; case 0x23: store_property (operand[0], operand[1], operand[2]); break; case 0x24: read_line (count, operand); break; case 0x25: print_character (operand[0]); break; case 0x26: print_number (operand[0]); break; case 0x27: ziprandom (operand[0]); break; case 0x28: push_var (operand[0]); break; case 0x29: pop_var (operand[0]); break; case 0x2a: set_status_size (operand[0]); break; case 0x2b: select_window (operand[0]); break; case 0x2c: call (count, operand, FUNCTION); break; case 0x2d: erase_window (operand[0]); break; case 0x2e: erase_line (operand[0]); break; case 0x2f: set_cursor_position (operand[0], operand[1]); break; case 0x31: set_video_attribute (operand[0]); break; case 0x32: set_format_mode (operand[0]); break; case 0x33: set_print_modes (operand[0], operand[1]); break; case 0x34: open_playback (operand[0]); break; case 0x35: sound (count, operand); break; case 0x36: read_character (count, operand); break; case 0x37: scan_data (count, operand); break; case 0x38: not (operand[0]); break; case 0x39: call (count, operand, PROCEDURE); break; case 0x3a: call (count, operand, PROCEDURE); break; case 0x3b: tokenise (count, operand); break; case 0x3c: encode (operand[0], operand[1], operand[2], operand[3]); break; case 0x3d: move_data (operand[0], operand[1], operand[2]); break; case 0x3e: print_window (count, operand); break; case 0x3f: check_argument (operand[0]); break; default: fatal ("Illegal operation"); } } else { /* Single operand class, load operand and execute instruction */ if (opcode < 0xb0) { operand[0] = load_operand ((opcode >> 4) & 0x03); switch ((char) opcode & 0x0f) { case 0x00: compare_zero (operand[0]); break; case 0x01: load_next_object (operand[0]); break; case 0x02: load_child_object (operand[0]); break; case 0x03: load_parent_object (operand[0]); break; case 0x04: load_property_length (operand[0]); break; case 0x05: increment (operand[0]); break; case 0x06: decrement (operand[0]); break; case 0x07: print_offset (operand[0]); break; case 0x08: call (1, operand, FUNCTION); break; case 0x09: remove_object (operand[0]); break; case 0x0a: print_object (operand[0]); break; case 0x0b: ret (operand[0]); break; case 0x0c: jump (operand[0]); break; case 0x0d: print_address (operand[0]); break; case 0x0e: load (operand[0]); break; case 0x0f: if (h_type > V4) call (1, operand, PROCEDURE); else not (operand[0]); break; } } else { /* Zero operand class, execute instruction */ switch ((char) opcode & 0x0f) { case 0x00: ret (TRUE); break; case 0x01: ret (FALSE); break; case 0x02: print_literal (); break; case 0x03: println_return (); break; case 0x05: save (count, operand); break; case 0x06: restore (count, operand); break; case 0x07: restart (); break; case 0x08: ret (stack[sp++]); break; case 0x09: get_fp (); break; case 0x0a: halt = TRUE; break; case 0x0b: new_line (); break; case 0x0c: display_status_line (); break; case 0x0d: verify (); break; case 0x0f: conditional_jump (TRUE); break; default: fatal ("Illegal operation"); } } } } return (interpreter_status); }/* interpret */ xzip/math.c0100600000076400007640000001106407173464736011657 0ustar zarfzarf/* * math.c * * Arithmetic, compare and logical instructions * */ #include "ztypes.h" /* * add * * Add two operands * */ #ifdef __STDC__ void add (zword_t a, zword_t b) #else void add (a, b) zword_t a, b; #endif { store_operand (a + b); }/* add */ /* * subtract * * Subtract two operands * */ #ifdef __STDC__ void subtract (zword_t a, zword_t b) #else void subtract (a, b) zword_t a, b; #endif { store_operand (a - b); }/* subtract */ /* * multiply * * Multiply two operands * */ #ifdef __STDC__ void multiply (zword_t a, zword_t b) #else void multiply (a, b) zword_t a, b; #endif { store_operand ((short)a * (short)b); }/* multiply */ /* * divide * * Divide two operands * */ #ifdef __STDC__ void divide (zword_t a, zword_t b) #else void divide (a, b) zword_t a, b; #endif { /* The magic rule is: round towards zero. */ short sa = (short)a; short sb = (short)b; short res; if (sb < 0) { sa = -sa; sb = -sb; } if (sa >= 0) { res = sa / sb; } else { res = -((-sa) / (sb)); } store_operand (res); }/* divide */ /* * remainder * * Modulus divide two operands * */ #ifdef __STDC__ void remainder (zword_t a, zword_t b) #else void remainder (a, b) zword_t a, b; #endif { /* The magic rule is: be consistent with divide, because (a/b)*a + (a%b) == a. So (a%b) has the same sign as a. */ short sa = (short)a; short sb = (short)b; short res; if (sb < 0) { sb = -sb; } if (sa >= 0) { res = sa % sb; } else { res = -((-sa) % (sb)); } store_operand (res); }/* remainder */ /* * shift * * Shift +/- n bits * */ #ifdef __STDC__ void shift (zword_t a, zword_t b) #else void shift (a, b) zword_t a; zword_t b; #endif { if ((short) b > 0) store_operand (a << (short) b); else store_operand (a >> abs ((short) b)); }/* shift */ /* * arith_shift * * Aritmetic shift +/- n bits * */ #ifdef __STDC__ void arith_shift (zword_t a, zword_t b) #else void arith_shift (a, b) zword_t a; zword_t b; #endif { if ((short) b >= 0) store_operand (a << (short) b); else if ((short) a >= 0) store_operand (a >> abs ((short) b)); else store_operand (~(((~a) & 0xFFFF) >> abs ((short) b))); }/* arith_shift */ /* * or * * Logical OR * */ #ifdef __STDC__ void or (zword_t a, zword_t b) #else void or (a, b) zword_t a, b; #endif { store_operand (a | b); }/* or */ /* * not * * Logical NOT * */ #ifdef __STDC__ void not (zword_t a) #else void not (a) zword_t a; #endif { store_operand (~a); }/* not */ /* * and * * Logical AND * */ #ifdef __STDC__ void and (zword_t a, zword_t b) #else void and (a, b) zword_t a, b; #endif { store_operand (a & b); }/* and */ /* * ziprandom * * Return random number between 1 and operand * */ #ifdef __STDC__ void ziprandom (zword_t a) #else void ziprandom (a) zword_t a; #endif { if (a == 0) store_operand (0); else if (a & 0x8000) { /* (a < 0) - used to set seed with #RANDOM */ SRANDOM_FUNC ((unsigned int) abs (a)); store_operand (0); } else /* (a > 0) */ store_operand (((zword_t) RANDOM_FUNC () % a) + 1); }/* ziprandom */ /* * test * * Jump if operand 2 bit mask not set in operand 1 * */ #ifdef __STDC__ void test (zword_t a, zword_t b) #else void test (a, b) zword_t a, b; #endif { conditional_jump (((~a) & b) == 0); }/* test */ /* * compare_zero * * Compare operand against zero * */ #ifdef __STDC__ void compare_zero (zword_t a) #else void compare_zero (a) zword_t a; #endif { conditional_jump (a == 0); }/* compare_zero */ /* * compare_je * * Jump if operand 1 is equal to any other operand * */ #ifdef __STDC__ void compare_je (int count, zword_t *operand) #else void compare_je (count, operand) int count; zword_t *operand; #endif { int i; for (i = 1; i < count; i++) if (operand[0] == operand[i]) { conditional_jump (TRUE); return; } conditional_jump (FALSE); }/* compare_je */ /* * compare_jl * * Jump if operand 1 is less than operand 2 * */ #ifdef __STDC__ void compare_jl (zword_t a, zword_t b) #else void compare_jl (a, b) zword_t a, b; #endif { conditional_jump ((short) a < (short) b); }/* compare_jl */ /* * compare_jg * * Jump if operand 1 is greater than operand 2 * */ #ifdef __STDC__ void compare_jg (zword_t a, zword_t b) #else void compare_jg (a, b) zword_t a, b; #endif { conditional_jump ((short) a > (short) b); }/* compare_jg */ xzip/memory.c0100600000076400007640000002251606706745010012226 0ustar zarfzarf/* * memory.c * * Code and data caching routines * */ #include "ztypes.h" /* A cache entry */ typedef struct cache_entry { struct cache_entry *flink; int page_number; zbyte_t data[PAGE_SIZE]; } cache_entry_t; /* Cache chain anchor */ static cache_entry_t *cache = NULL; /* Pseudo translation buffer, one entry each for code and data pages */ static unsigned int current_code_page = 0; static cache_entry_t *current_code_cachep = NULL; static unsigned int current_data_page = 0; static cache_entry_t *current_data_cachep = NULL; #ifdef __STDC__ static unsigned int calc_data_pages (void); static cache_entry_t *update_cache (int); #else static unsigned int calc_data_pages (); static cache_entry_t *update_cache (); #endif /* * load_cache * * Initialise the cache and any other dynamic memory objects. The memory * required can be split into two areas. Firstly, three buffers are required for * input, output and status line. Secondly, two data areas are required for * writeable data and read only data. The writeable data is the first chunk of * the file and is put into non-paged cache. The read only data is the remainder * of the file which can be paged into the cache as required. Writeable data has * to be memory resident because it cannot be written out to a backing store. * */ #ifdef __STDC__ void load_cache (void) #else void load_cache () #endif { unsigned long file_size; unsigned int i, file_pages, data_pages; cache_entry_t *cachep; /* Allocate output and status line buffers */ /* output buffer is now handled elsewhere --zarf */ /*line = (char *) malloc (screen_cols + 1); if (line == NULL) fatal ("Insufficient memory to play game");*/ status_line = (char *) malloc (screen_cols + 1); if (status_line == NULL) fatal ("Insufficient memory to play game"); /* Must have at least one cache page for memory calculation */ cachep = (cache_entry_t *) malloc (sizeof (cache_entry_t)); if (cachep == NULL) fatal ("Insufficient memory to play game"); cachep->flink = cache; cachep->page_number = 0; cache = cachep; /* Calculate dynamic cache pages required */ if (h_config & CONFIG_MAX_DATA) data_pages = calc_data_pages (); else data_pages = (h_data_size + PAGE_MASK) >> PAGE_SHIFT; data_size = data_pages * PAGE_SIZE; file_size = (unsigned long) h_file_size * story_scaler; file_pages = (unsigned int) ((file_size + PAGE_MASK) >> PAGE_SHIFT); /* Allocate static data area and initialise it */ datap = (zbyte_t *) malloc (data_size); if (datap == NULL) fatal ("Insufficient memory to play game"); for (i = 0; i < data_pages; i++) read_page (i, &datap[i * PAGE_SIZE]); /* Allocate memory for undo */ undo_datap = (zbyte_t *) malloc (data_size); /* Allocate cache pages and initialise them */ for (i = data_pages; cachep != NULL && i < file_pages; i++) { cachep = (cache_entry_t *) malloc (sizeof (cache_entry_t)); if (cachep != NULL) { cachep->flink = cache; cachep->page_number = i; read_page (cachep->page_number, cachep->data); cache = cachep; } } }/* load_cache */ /* * unload_cache * * Deallocate cache and other memory objects. * */ #ifdef __STDC__ void unload_cache (void) #else void unload_cache () #endif { cache_entry_t *cachep, *nextp; /* Make sure all output has been flushed */ new_line (); /* Free output buffer, status line and data memory */ /*free (line); */ /* this is gone now. --zarf */ free (status_line); status_line = NULL; free (datap); datap = NULL; free (undo_datap); undo_datap = NULL; /* Free cache memory */ for (cachep = cache; cachep->flink != NULL; cachep = nextp) { nextp = cachep->flink; free (cachep); } }/* unload_cache */ /* * read_code_word * * Read a word from the instruction stream. * */ #ifdef __STDC__ zword_t read_code_word (void) #else zword_t read_code_word () #endif { zword_t w; w = (zword_t) read_code_byte () << 8; w |= (zword_t) read_code_byte (); return (w); }/* read_code_word */ /* * read_code_byte * * Read a byte from the instruction stream. * */ #ifdef __STDC__ zbyte_t read_code_byte (void) #else zbyte_t read_code_byte () #endif { unsigned int page_number, page_offset; /* Calculate page and offset values */ page_number = (unsigned int) (pc >> PAGE_SHIFT); page_offset = (unsigned int) pc & PAGE_MASK; /* Load page into translation buffer */ if (page_number != current_code_page) { current_code_cachep = update_cache (page_number); current_code_page = page_number; } /* Update the PC */ pc++; /* Return byte from page offset */ return (current_code_cachep->data[page_offset]); }/* read_code_byte */ /* * read_data_word * * Read a word from the data area. * */ #ifdef __STDC__ zword_t read_data_word (unsigned long *addr) #else zword_t read_data_word (addr) unsigned long *addr; #endif { zword_t w; w = (zword_t) read_data_byte (addr) << 8; w |= (zword_t) read_data_byte (addr); return (w); }/* read_data_word */ /* * read_data_byte * * Read a byte from the data area. * */ #ifdef __STDC__ zbyte_t read_data_byte (unsigned long *addr) #else zbyte_t read_data_byte (addr) unsigned long *addr; #endif { unsigned int page_number, page_offset; zbyte_t value; /* Check if byte is in non-paged cache */ if (*addr < (unsigned long) data_size) value = datap[*addr]; else { /* Calculate page and offset values */ page_number = (int) (*addr >> PAGE_SHIFT); page_offset = (int) *addr & PAGE_MASK; /* Load page into translation buffer */ if (page_number != current_data_page) { current_data_cachep = update_cache (page_number); current_data_page = page_number; } /* Fetch byte from page offset */ value = current_data_cachep->data[page_offset]; } /* Update the address */ (*addr)++; return (value); }/* read_data_byte */ /* * calc_data_pages * * Compute the best size for the data area cache. Some games have the data size * header parameter set too low. This causes a write outside of data area on * some games. To alleviate this problem the data area size is set to the * maximum of the restart size, the data size and the end of the dictionary. An * attempt is made to put the dictionary in the data area to stop paging during * a dictionary lookup. Some games have the dictionary end very close to the * 64K limit which may cause problems for machines that allocate memory in * 64K chunks. * */ #ifdef __STDC__ static unsigned int calc_data_pages (void) #else static unsigned int calc_data_pages () #endif { unsigned long offset, data_end, dictionary_end; int separator_count, word_size, word_count; unsigned int data_pages; /* Calculate end of data area, use restart size if data size is too low */ if (h_data_size > h_restart_size) data_end = h_data_size; else data_end = h_restart_size; /* Calculate end of dictionary table */ offset = h_words_offset; separator_count = read_data_byte (&offset); offset += separator_count; word_size = read_data_byte (&offset); word_count = read_data_word (&offset); dictionary_end = offset + (word_size * word_count); /* If data end is too low then use end of dictionary instead */ if (dictionary_end > data_end) data_pages = (unsigned int) ((dictionary_end + PAGE_MASK) >> PAGE_SHIFT); else data_pages = (unsigned int) ((data_end + PAGE_MASK) >> PAGE_SHIFT); return (data_pages); }/* calc_data_pages */ /* * update_cache * * Called on a code or data page cache miss to find the page in the cache or * read the page in from disk. The chain is kept as a simple LRU chain. If a * page cannot be found then the page on the end of the chain is reused. If the * page is found, or reused, then it is moved to the front of the chain. * */ #ifdef __STDC__ static cache_entry_t *update_cache (int page_number) #else static cache_entry_t *update_cache (page_number) int page_number; #endif { cache_entry_t *cachep, *lastp; /* Search the cache chain for the page */ for (lastp = cache, cachep = cache; cachep->flink != NULL && cachep->page_number && cachep->page_number != page_number; lastp = cachep, cachep = cachep->flink) ; /* If no page in chain then read it from disk */ if (cachep->page_number != page_number) { /* Reusing last cache page, so invalidate cache if page was in use */ if (cachep->flink == NULL && cachep->page_number) { if (current_code_page == (unsigned int) cachep->page_number) current_code_page = 0; if (current_data_page == (unsigned int) cachep->page_number) current_data_page = 0; } /* Load the new page number and the page contents from disk */ cachep->page_number = page_number; read_page (page_number, cachep->data); } /* If page is not at front of cache chain then move it there */ if (lastp != cache) { lastp->flink = cachep->flink; cachep->flink = cache; cache = cachep; } return (cachep); }/* update_cache */ xzip/object.c0100600000076400007640000002276306551763103012171 0ustar zarfzarf/* * object.c * * Object manipulation routines. * */ #include "ztypes.h" #define PARENT 0 #define NEXT 1 #define CHILD 2 #ifdef __STDC__ static zword_t read_object (zword_t objp, int field); static void write_object (zword_t objp, int field, zword_t value); #else static zword_t read_object (); static void write_object (); #endif /* * get_object_address * * Calculate the address of an object in the data area. * */ #ifdef __STDC__ zword_t get_object_address (zword_t obj) #else zword_t get_object_address (obj) zword_t obj; #endif { int offset; /* Address calculation is object table base + size of default properties area + object number-1 * object size */ if (h_type < V4) offset = h_objects_offset + ((P3_MAX_PROPERTIES - 1) * 2) + ((obj - 1) * O3_SIZE); else offset = h_objects_offset + ((P4_MAX_PROPERTIES - 1) * 2) + ((obj - 1) * O4_SIZE); return ((zword_t) offset); }/* get_object_address */ /* * insert_object * * Insert object 1 as the child of object 2 after first removing it from its * previous parent. The object is inserted at the front of the child object * chain. * */ #ifdef __STDC__ void insert_object (zword_t obj1, zword_t obj2) #else void insert_object (obj1, obj2) zword_t obj1; zword_t obj2; #endif { zword_t obj1p, obj2p, child2; #ifdef STRICTZ if (obj1 == 0) { report_strictz_error(STRZERR_MOVE_OBJECT, "@move_object called moving object 0"); return; } if (obj2 == 0) { report_strictz_error(STRZERR_MOVE_OBJECT_2, "@move_object called moving into object 0"); return; } #endif /* Get addresses of both objects */ obj1p = get_object_address (obj1); obj2p = get_object_address (obj2); /* Remove object 1 from current parent */ remove_object (obj1); /* Make object 2 object 1's parent */ write_object (obj1p, PARENT, obj2); /* Get current first child of object 2 */ child2 = read_object (obj2p, CHILD); /* Make object 1 first child of object 2 */ write_object (obj2p, CHILD, obj1); /* If object 2 had children then link them into the next child field of object 1 */ if (child2) write_object (obj1p, NEXT, child2); }/* insert_object */ /* * remove_object * * Remove an object by unlinking from the its parent object and from its * siblings. * */ #ifdef __STDC__ void remove_object (zword_t obj) #else void remove_object (obj) zword_t obj; #endif { zword_t objp, parentp, childp, parent, child; #ifdef STRICTZ if (obj == 0) { report_strictz_error(STRZERR_REMOVE_OBJECT, "@remove_object called with object 0"); return; } #endif /* Get address of object to be removed */ objp = get_object_address (obj); /* Get parent of object, and return if no parent */ if ((parent = read_object (objp, PARENT)) == 0) return; /* Get address of parent object */ parentp = get_object_address (parent); /* Find first child of parent */ child = read_object (parentp, CHILD); /* If object is first child then just make the parent child pointer equal to the next child */ if (child == obj) write_object (parentp, CHILD, read_object (objp, NEXT)); else { /* Walk down the child chain looking for this object */ do { childp = get_object_address (child); child = read_object (childp, NEXT); } while (child != obj); /* Set the next pointer thre previous child to the next pointer of the current object child pointer */ write_object (childp, NEXT, read_object (objp, NEXT)); } /* Set the parent and next child pointers to NULL */ write_object (objp, PARENT, 0); write_object (objp, NEXT, 0); }/* remove_object */ /* * load_parent_object * * Load the parent object pointer of an object * */ #ifdef __STDC__ void load_parent_object (zword_t obj) #else void load_parent_object (obj) zword_t obj; #endif { #ifdef STRICTZ if (obj == 0) { report_strictz_error(STRZERR_GET_PARENT, "@get_parent called with object 0"); store_operand(0); return; } #endif store_operand (read_object (get_object_address (obj), PARENT)); }/* load_parent_object */ /* * load_child_object * * Load the child object pointer of an object and jump if the child pointer is * not NULL. * */ #ifdef __STDC__ void load_child_object (zword_t obj) #else void load_child_object (obj) zword_t obj; #endif { zword_t child; #ifdef STRICTZ if (obj == 0) { report_strictz_error(STRZERR_GET_CHILD, "@get_child called with object 0"); store_operand(0); conditional_jump(FALSE); return; } #endif child = read_object (get_object_address (obj), CHILD); store_operand (child); conditional_jump (child != 0); }/* load_child_object */ /* * load_next_object * * Load the next child object pointer of an object and jump if the next child * pointer is not NULL. * */ #ifdef __STDC__ void load_next_object (zword_t obj) #else void load_next_object (obj) zword_t obj; #endif { zword_t next; #ifdef STRICTZ if (obj == 0) { report_strictz_error(STRZERR_GET_SIBLING, "@get_sibling called with object 0"); store_operand(0); conditional_jump(FALSE); return; } #endif next = read_object (get_object_address (obj), NEXT); store_operand (next); conditional_jump (next != 0); }/* load_next_object */ /* * compare_parent_object * * Jump if object 2 is the parent of object 1 * */ #ifdef __STDC__ void compare_parent_object (zword_t obj1, zword_t obj2) #else void compare_parent_object (obj1, obj2) zword_t obj1; zword_t obj2; #endif { #ifdef STRICTZ if (obj1 == 0) { report_strictz_error(STRZERR_JIN, "@jin called with object 0"); conditional_jump(0 == obj2); return; } #endif conditional_jump (read_object (get_object_address (obj1), PARENT) == obj2); }/* compare_parent_object */ /* * test_attr * * Test if an attribute bit is set. * */ #ifdef __STDC__ void test_attr (zword_t obj, zword_t bit) #else void test_attr (obj, bit) zword_t obj; zword_t bit; #endif { zword_t objp; zbyte_t value; assert (O3_ATTRIBUTES == O4_ATTRIBUTES); #ifdef STRICTZ if (obj == 0) { report_strictz_error(STRZERR_TEST_ATTR, "@test_attr called with object 0"); conditional_jump(FALSE); return; } #endif /* Get attribute address */ objp = get_object_address (obj) + (bit >> 3); /* Load attribute byte */ value = get_byte (objp); /* Test attribute */ conditional_jump ((value >> (7 - (bit & 7))) & 1); }/* test_attr */ /* * set_attr * * Set an attribute bit. * */ #ifdef __STDC__ void set_attr (zword_t obj, zword_t bit) #else void set_attr (obj, bit) zword_t obj; zword_t bit; #endif { zword_t objp; zbyte_t value; assert (O3_ATTRIBUTES == O4_ATTRIBUTES); #ifdef STRICTZ if (obj == 0) { report_strictz_error(STRZERR_SET_ATTR, "@set_attr called with object 0"); return; } #endif /* Get attribute address */ objp = get_object_address (obj) + (bit >> 3); /* Load attribute byte */ value = get_byte (objp); /* Set attribute bit */ value |= (zbyte_t) (1 << (7 - (bit & 7))); /* Store attribute byte */ set_byte (objp, value); }/* set_attr */ /* * clear_attr * * Clear an attribute bit * */ #ifdef __STDC__ void clear_attr (zword_t obj, zword_t bit) #else void clear_attr (obj, bit) zword_t obj; zword_t bit; #endif { zword_t objp; zbyte_t value; assert (O3_ATTRIBUTES == O4_ATTRIBUTES); #ifdef STRICTZ if (obj == 0) { report_strictz_error(STRZERR_CLEAR_ATTR, "@clear_attr called with object 0"); return; } #endif /* Get attribute address */ objp = get_object_address (obj) + (bit >> 3); /* Load attribute byte */ value = get_byte (objp); /* Clear attribute bit */ value &= (zbyte_t) ~(1 << (7 - (bit & 7))); /* Store attribute byte */ set_byte (objp, value); }/* clear_attr */ #ifdef __STDC__ static zword_t read_object (zword_t objp, int field) #else static zword_t read_object (objp, field) zword_t objp; int field; #endif { zword_t value; if (h_type < V4) { if (field == PARENT) value = (zword_t) get_byte (PARENT3 (objp)); else if (field == NEXT) value = (zword_t) get_byte (NEXT3 (objp)); else value = (zword_t) get_byte (CHILD3 (objp)); } else { if (field == PARENT) value = get_word (PARENT4 (objp)); else if (field == NEXT) value = get_word (NEXT4 (objp)); else value = get_word (CHILD4 (objp)); } return (value); }/* read_object */ #ifdef __STDC__ static void write_object (zword_t objp, int field, zword_t value) #else static void write_object (objp, field, value) zword_t objp; int field; zword_t value; #endif { if (h_type < V4) { if (field == PARENT) set_byte (PARENT3 (objp), value); else if (field == NEXT) set_byte (NEXT3 (objp), value); else set_byte (CHILD3 (objp), value); } else { if (field == PARENT) set_word (PARENT4 (objp), value); else if (field == NEXT) set_word (NEXT4 (objp), value); else set_word (CHILD4 (objp), value); } }/* write_object */ xzip/operand.c0100600000076400007640000001071206551763103012342 0ustar zarfzarf/* * operand.c * * Operand manipulation routines * */ #include "ztypes.h" /* * load_operand * * Load an operand, either: a variable, popped from the stack or a literal. * */ #ifdef __STDC__ zword_t load_operand (int type) #else zword_t load_operand (type) int type; #endif { zword_t operand; if (type) { /* Type 1: byte literal, or type 2: operand specifier */ operand = (zword_t) read_code_byte (); if (type == 2) { /* If operand specifier non-zero then it's a variable, otherwise it's the top of the stack */ if (operand) operand = load_variable (operand); else operand = stack[sp++]; } } else /* Type 0: word literal */ operand = read_code_word (); return (operand); }/* load_operand */ /* * store_operand * * Store an operand, either as a variable pushed on the stack. * */ #ifdef __STDC__ void store_operand (zword_t operand) #else void store_operand (operand) zword_t operand; #endif { zbyte_t specifier; /* Read operand specifier byte */ specifier = read_code_byte (); /* If operand specifier non-zero then it's a variable, otherwise it's the pushed on the stack */ if (specifier) store_variable (specifier, operand); else stack[--sp] = operand; }/* store_operand */ /* * load_variable * * Load a variable, either: a stack local variable, a global variable or the top * of the stack. * */ #ifdef __STDC__ zword_t load_variable (int number) #else zword_t load_variable (number) int number; #endif { zword_t variable; if (number) { if (number < 16) /* number in range 1 - 15, it's a stack local variable */ variable = stack[fp - (number - 1)]; else /* number > 15, it's a global variable */ variable = get_word (h_globals_offset + ((number - 16) * 2)); } else /* number = 0, get from top of stack */ variable = stack[sp]; return (variable); }/* load_variable */ /* * store_variable * * Store a variable, either: a stack local variable, a global variable or the top * of the stack. * */ #ifdef __STDC__ void store_variable (int number, zword_t variable) #else void store_variable (number, variable) int number; zword_t variable; #endif { if (number) { if (number < 16) /* number in range 1 - 15, it's a stack local variable */ stack[fp - (number - 1)] = variable; else /* number > 15, it's a global variable */ set_word (h_globals_offset + ((number - 16) * 2), variable); } else /* number = 0, get from top of stack */ stack[sp] = variable; }/* store_variable */ /* * conditional_jump * * Take a jump after an instruction based on the flag, either true or false. The * jump can be modified by the change logic flag. Normally jumps are taken * when the flag is true. When the change logic flag is set then the jump is * taken when flag is false. A PC relative jump can also be taken. This jump can * either be a positive or negative byte or word range jump. An additional * feature is the return option. If the jump offset is zero or one then that * literal value is passed to the return instruction, instead of a jump being * taken. Complicated or what! * */ #ifdef __STDC__ void conditional_jump (int flag) #else void conditional_jump (flag) int flag; #endif { zbyte_t specifier; zword_t offset; /* Read the specifier byte */ specifier = read_code_byte (); /* If the reverse logic flag is set then reverse the flag */ if (specifier & 0x80) flag = (flag) ? 0 : 1; /* Jump offset is in bottom 6 bits */ offset = (zword_t) specifier & 0x3f; /* If the byte range jump flag is not set then load another offset byte */ if ((specifier & 0x40) == 0) { /* Add extra offset byte to existing shifted offset */ offset = (offset << 8) + read_code_byte (); /* If top bit of offset is set then propogate the sign bit */ if (offset & 0x2000) offset |= 0xc000; } /* If the flag is false then do the jump */ if (flag == 0) /* If offset equals 0 or 1 return that value instead */ if (offset == 0 || offset == 1) ret (offset); else /* Add offset to PC */ pc = (unsigned long) (pc + (short) offset - 2); }/* conditional_jump */ xzip/pickle.c0100600000076400007640000001661106551763103012165 0ustar zarfzarf#include #include #include #include "ztypes.h" #include "pickle.h" /* This file is the source code for the PICKLE Reader Library. Version 1. */ /* This library is a very simple one, intended for use in interpreters that want to support reading PICKLE files. This library does not have functions to write or analyze PICKLE files, just to read them in the rather limited way that interpreters should want to. */ #ifdef BIG_END_MODE static char contentmessage[] = "\nPICKLE Reader Library 1.0.0 (big-endian)\n"; #endif #ifdef LITTLE_END_MODE static char contentmessage[] = "\nPICKLE Reader Library 1.0.0 (little-endian)\n"; #endif #ifdef __STDC__ static char contentmessage2[] = "\nLibrary compiled with __STDC__\n"; #else static char contentmessage2[] = "\nLibrary compiled without __STDC__\n"; #endif #define pik_InitedMagic (0x18328EEB) #if defined(BIG_END_MODE) || defined(LITTLE_END_MODE) #ifdef BIG_END_MODE #define pikNative(v) (v) #endif #ifdef LITTLE_END_MODE #define pikNative(v) ( \ ((((long)(v)) >> 24) & 0x000000ff) \ | ((((long)(v)) >> 8) & 0x0000ff00) \ | ((((long)(v)) << 8) & 0x00ff0000) \ | ((((long)(v)) << 24) & 0xff000000) \ ) #endif #else #define pikNative(v) (0) #endif struct pikDescriptorData { pikType use; pikLong number; pikType format; pikLong formatversion; pikLong startpos; pikLong length; void *data; /* (non-Mac systems) */ /*Handle data;*/ /* (Mac only) */ }; typedef struct pikDescriptorData pikDescriptor; struct pikMapData { pikLong inited; /* contains pik_InitedMagic while the map is in existence */ FILE *file; /* (non-Mac systems) */ /*short file;*/ /* (Mac only) */ pikLong numchunks; pikLong filelength; pikDescriptor *chunks; /* pointer to an array of descriptors */ }; typedef struct pikMapData pikMap; #ifdef __STDC__ short pikIsPickleHeader(char *header) #else short pikIsPickleHeader(header) char *header; #endif { if (header[0] == 0x70 && header[1] == 0x69 && header[2] == 0x6b && header[3] == 0x6c) { return TRUE; } else { return FALSE; } } #ifdef __STDC__ pikErr pikCreateMap(FILE *file, pikMapPtr *newmap) #else pikErr pikCreateMap(file, newmap) FILE *file; pikMapPtr *newmap; #endif { pikMapPtr map; pikLong buffer[6]; int err; long count; long lx; pikLong numchunks; pikLong filelength; pikDescriptor *chunks; if (sizeof(pikLong) != 4) { return pikerr_WrongSizeInts; } { pikLong testval; unsigned char *cx; cx = (unsigned char *)(&testval); cx[0] = 0x12; cx[1] = 0x34; cx[2] = 0x56; cx[3] = 0x78; if (pikNative(testval) != 0x12345678) { return pikerr_WrongEndian; } } if (!file) { return pikerr_BadOption; } err = fseek(file, 0, 0); if (err) { return pikerr_CantRead; } count = fread(buffer, 1, 16, file); if (count != 16) { return pikerr_CantRead; } if (pikNative(buffer[0]) != pikMakeType('p', 'i', 'k', 'l') || pikNative(buffer[1]) != 1) { return pikerr_NotAMap; } numchunks = pikNative(buffer[2]); filelength = pikNative(buffer[3]); err = fseek(file, 0, 2); if (err) { return pikerr_CantRead; } count = ftell(file); if (count == (-1)) { return pikerr_CantRead; } if (count != filelength) { return pikerr_NotAMap; } err = fseek(file, 16, 0); if (err) { return pikerr_CantRead; } map = (pikMapPtr)malloc(sizeof(pikMap)); if (!map) { return pikerr_Memory; } chunks = (pikDescriptor *)malloc(sizeof(pikDescriptor) * numchunks); if (!chunks) { free(map); return pikerr_Memory; } for (lx=0; lxchunks = chunks; map->numchunks = numchunks; map->filelength = filelength; map->file = file; map->inited = pik_InitedMagic; *newmap = map; return pikerr_None; } #ifdef __STDC__ pikErr pikDestroyMap(pikMapPtr map) #else pikErr pikDestroyMap(map) pikMapPtr map; #endif { pikLong lx; pikDescriptor *desc; if (!map || !map->chunks || map->inited != pik_InitedMagic) { return pikerr_NotAMap; } for (lx=0; lxnumchunks; lx++) { desc = (&(map->chunks[lx])); if (desc->data) { free(desc->data); desc->data = NULL; } } map->inited = 0; free(map->chunks); free(map); return pikerr_None; } #ifdef __STDC__ pikErr pikFindChunk(pikMapPtr map, pikType use, pikLong number, short numformats, pikFormat *formatlist, pikChunkID *idfound) #else pikErr pikFindChunk(map, use, number, numformats, formatlist, idfound) pikMapPtr map; pikType use; pikLong number; short numformats; pikFormat *formatlist; pikChunkID *idfound; #endif { pikDescriptor *desc; pikLong id, bestid; short fx, sofar; if (!map || !map->chunks || map->inited != pik_InitedMagic) { return pikerr_NotAMap; } if (numformats < 0 || (numformats > 0 && !formatlist)) { return pikerr_BadOption; } sofar = (-1); for (id=0, desc=map->chunks; idnumchunks; id++, desc++) { if (desc->use == use && desc->number == number) { if (numformats == 0) { if (idfound) *idfound = id; return pikerr_None; } for (fx=0; fxformat == formatlist[fx].name && desc->formatversion == formatlist[fx].version) { if (sofar < 0 || fx < sofar) { sofar = fx; bestid = id; } } } } } if (sofar >= 0) { if (idfound) *idfound = bestid; return pikerr_None; } if (idfound) *idfound = pik_NoChunk; return pikerr_NotFound; } #ifdef __STDC__ pikErr pikLoadChunk(pikMapPtr map, pikChunkID id, short method, pikChunk *found) #else pikErr pikLoadChunk(map, id, method, found) pikMapPtr map; pikChunkID id; short method; pikChunk *found; #endif { pikDescriptor *desc; if (!map || !map->chunks || map->inited != pik_InitedMagic) { return pikerr_NotAMap; } if (id < 0 || id >= map->numchunks) { return pikerr_BadOption; } if (!found) { return pikerr_BadOption; } desc = (&(map->chunks[id])); switch (method) { case pikmethod_DontRead: break; case pikmethod_FilePos: found->data.startpos = desc->startpos; break; case pikmethod_Memory: if (!desc->data) { long count; int err; desc->data = malloc(desc->length); if (!desc->data) { return pikerr_Memory; } err = fseek(map->file, desc->startpos, 0); if (err) { return pikerr_CantRead; } count = fread(desc->data, 1, desc->length, map->file); if (count != desc->length) { return pikerr_CantRead; } } found->data.ptr = desc->data; break; default: return pikerr_BadOption; } found->length = desc->length; found->format.name = desc->format; found->format.version = desc->formatversion; return pikerr_None; } #ifdef __STDC__ pikErr pikUnloadChunk(pikMapPtr map, pikChunkID id) #else pikErr pikUnloadChunk(map, id) pikMapPtr map; pikChunkID id; #endif { pikDescriptor *desc; if (!map || !map->chunks || map->inited != pik_InitedMagic) { return pikerr_NotAMap; } if (id < 0 || id >= map->numchunks) { return pikerr_BadOption; } desc = (&(map->chunks[id])); if (desc->data) { free(desc->data); desc->data = NULL; return pikerr_None; } else { return pikerr_NotFound; } } xzip/pickle.h0100600000076400007640000000453006551763103012167 0ustar zarfzarf /* This file defines the API for the PICKLE Reader Library. Version 1. */ /* This library is a very simple one, intended for use in interpreters that want to support reading PICKLE files. This library does not have functions to write or analyze PICKLE files, just to read them in the rather limited way that interpreters should want to. */ /* First, a few definitions which you may have to customize for your machine. */ /* pikLong must be typedef'd as a 32-bit signed integer. If "long" is not 32 bits on your system, change this line. */ typedef long pikLong; /* BIG_END_MODE or LITTLE_END_MODE is defined by the Makefile. */ /* Now some Useful Constants */ #define pikerr_None (0) #define pikerr_NotFound (1) #define pikerr_BadOption (2) #define pikerr_NotAMap (3) #define pikerr_CantRead (4) #define pikerr_Memory (5) #define pikerr_WrongSizeInts (11) #define pikerr_WrongEndian (12) #define pikmethod_DontRead (0) #define pikmethod_FilePos (1) #define pikmethod_Memory (2) #define pik_NoChunk (-1) #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif typedef pikLong pikType; typedef short pikErr; #define pikMakeType(c1, c2, c3, c4) \ ((((pikType)(c1)) << 24) | (((pikType)(c2)) << 16) \ | (((pikType)(c3)) << 8) | ((pikType)(c4))) typedef struct pikMapData *pikMapPtr; struct pikFormatData { pikType name; pikLong version; }; typedef struct pikFormatData pikFormat; typedef pikLong pikChunkID; struct pikChunkData { union { pikLong startpos; /* Set by pikmethod_FilePos */ void *ptr; /* Set by pikmethod_Memory (non-Mac systems) */ /*Handle han;*/ /* Set by pikmethod_Memory (Mac only) */ } data; pikLong length; pikFormat format; }; typedef struct pikChunkData pikChunk; #ifdef __STDC__ extern short pikIsPickleHeader(char *header); extern pikErr pikCreateMap(FILE *file, pikMapPtr *newmap); extern pikErr pikDestroyMap(pikMapPtr map); extern pikErr pikFindChunk(pikMapPtr map, pikType use, pikLong number, short numformats, pikFormat *formatlist, pikChunkID *idfound); extern pikErr pikLoadChunk(pikMapPtr map, pikChunkID id, short method, pikChunk *found); extern pikErr pikUnloadChunk(pikMapPtr map, pikChunkID id); #else extern short pikIsPickleHeader(); extern pikErr pikCreateMap(); extern pikErr pikDestroyMap(); extern pikErr pikFindChunk(); extern pikErr pikLoadChunk(); extern pikErr pikUnloadChunk(); #endif xzip/property.c0100600000076400007640000003013007173474366012605 0ustar zarfzarf/* * property.c * * Property manipulation routines * */ #include "ztypes.h" /* * get_property_addr * * Calculate the address of the start of the property list associated with an * object. * */ #ifdef __STDC__ static zword_t get_property_addr (zword_t obj) #else static zword_t get_property_addr (obj) zword_t obj; #endif { zword_t offset, prop; /* Calculate the address of the property pointer in the object */ offset = get_object_address (obj); offset += (h_type < V4) ? O3_PROPERTY_OFFSET : O4_PROPERTY_OFFSET; /* Read the property pointer */ prop = get_word (offset); /* Skip past object description which is an ASCIC of encoded words */ prop += (get_byte (prop) * 2) + 1; return (prop); }/* get_property_adr */ /* * get_next_property * * Calculate the address of the next property in a property list. * */ #ifdef __STDC__ static zword_t get_next_property (zword_t propp) #else static zword_t get_next_property (propp) zword_t propp; #endif { zbyte_t value; /* Load the current property id */ value = get_byte (propp++); /* Calculate the length of this property */ if (h_type < V4) value = (zbyte_t) ((value & property_size_mask) >> 5); else if (value & 0x80) { value = get_byte (propp) & (zbyte_t) property_size_mask; if (value == 0) value = 64; } else if (value & 0x40) value = 1; else value = 0; /* Address property length + 1 to current property pointer */ return ((zword_t) (propp + value + 1)); }/* get_next_property */ /* * load_property * * Load a property from a property list. Properties are held in list sorted by * property id, with highest ids first. There is also a concept of a default * property for loading only. The default properties are held in a table pointed * to be the object pointer, and occupy the space before the first object. * */ #ifdef __STDC__ void load_property (zword_t obj, zword_t prop) #else void load_property (obj, prop) zword_t obj; zword_t prop; #endif { zword_t propp; #ifdef STRICTZ if (obj == 0) { report_strictz_error(STRZERR_GET_PROP, "@get_prop called with object 0"); store_operand (0); return; } #endif /* Load address of first property */ propp = get_property_addr (obj); /* Scan down the property list while the target property id is less than the property id in the list */ while ((zbyte_t) (get_byte (propp) & property_mask) > (zbyte_t) prop) propp = get_next_property (propp); /* If the property ids match then load the first property */ if ((zbyte_t) (get_byte (propp) & property_mask) == (zbyte_t) prop) { /* Only load first property if it is a byte sized property */ if ((get_byte (propp++) & property_size_mask) == 0) { store_operand (get_byte (propp)); return; } } else /* Calculate the address of the default property */ propp = h_objects_offset + ((prop - 1) * 2); /* Load the first property word */ store_operand (get_word (propp)); }/* load_property */ /* * store_property * * Store a property value in a property list. The property must exist in the * property list to be replaced. * */ #ifdef __STDC__ void store_property (zword_t obj, zword_t prop, zword_t value) #else void store_property (obj, prop, value) zword_t obj; zword_t prop; zword_t value; #endif { zword_t propp; #ifdef STRICTZ if (obj == 0) { report_strictz_error(STRZERR_PUT_PROP, "@put_prop called with object 0"); return; } #endif /* Load address of first property */ propp = get_property_addr (obj); /* Scan down the property list while the target property id is less than the property id in the list */ while ((zbyte_t) (get_byte (propp) & property_mask) > (zbyte_t) prop) propp = get_next_property (propp); /* If the property id was found then store a new value, otherwise complain */ if ((zbyte_t) (get_byte (propp) & property_mask) == (zbyte_t) prop) { /* Determine if this is a byte or word sized property */ if ((get_byte (propp++) & property_size_mask) == 0) set_byte (propp, value); else set_word (propp, value); } else fatal ("No such property"); }/* store_property */ /* * load_next_property * * Load the property after the current property. If the current property is zero * then load the first property. * */ #ifdef __STDC__ void load_next_property (zword_t obj, zword_t prop) #else void load_next_property (obj, prop) zword_t obj; zword_t prop; #endif { zword_t propp; #ifdef STRICTZ if (obj == 0) { report_strictz_error(STRZERR_GET_NEXT_PROP, "@get_next_prop called with object 0"); store_operand (0); return; } #endif /* Load address of first property */ propp = get_property_addr (obj); /* If the property id is non zero then find the next property */ if (prop) { /* Scan down the property list while the target property id is less than the property id in the list */ while ((zbyte_t) (get_byte (propp) & property_mask) > (zbyte_t) prop) propp = get_next_property (propp); /* If the property id was found then get the next property, otherwise complain */ if ((zbyte_t) (get_byte (propp) & property_mask) == (zbyte_t) prop) propp = get_next_property (propp); else fatal ("No such property"); } /* Return the next property id */ store_operand (get_byte (propp) & property_mask); }/* load_next_property */ /* * load_property_address * * Load the address address of the data associated with a property. * */ #ifdef __STDC__ void load_property_address (zword_t obj, zword_t prop) #else void load_property_address (obj, prop) zword_t obj; zword_t prop; #endif { zword_t propp; #ifdef STRICTZ if (obj == 0) { report_strictz_error(STRZERR_GET_PROP_ADDR, "@get_prop_addr called with object 0"); store_operand (0); return; } #endif /* Load address of first property */ propp = get_property_addr (obj); /* Scan down the property list while the target property id is less than the property id in the list */ while ((zbyte_t) (get_byte (propp) & property_mask) > (zbyte_t) prop) propp = get_next_property (propp); /* If the property id was found then calculate the property address, otherwise return zero */ if ((zbyte_t) (get_byte (propp) & property_mask) == (zbyte_t) prop) { /* Skip past property id, can be a byte or a word */ if (h_type > V3 && (get_byte (propp) & 0x80)) propp++; propp++; store_operand (propp); } else /* No property found, just return 0 */ store_operand (0); }/* load_property_address */ /* * load_property_length * * Load the length of a property. * */ #ifdef __STDC__ void load_property_length (zword_t propp) #else void load_property_length (propp) zword_t propp; #endif { /* Back up the property pointer to the property id */ propp--; if (h_type < V4) /* Property length is in high bits of property id */ store_operand (((get_byte (propp) & property_size_mask ) >> 5) + 1); else if (get_byte (propp) & 0x80) { /* Property length is in property id */ int val = get_byte (propp) & property_size_mask; if (val == 0) val = 64; store_operand (val); } else /* Word sized property if bit 6 set, else byte sized property */ store_operand ((get_byte (propp) & 0x40) ? 2 : 1); }/* load_property_length */ /* * scan_data * * Scan an array of bytes or words looking for a target byte or word. The * optional 4th parameter can set the address step and also whether to scan a * byte array. * */ #ifdef __STDC__ void scan_data (int argc, zword_t *argv) #else void scan_data (argc, argv) int argc; zword_t *argv; #endif { unsigned long address; unsigned int i, step; /* Supply default parameters */ if (argc < 4) argv[3] = 0x82; address = argv[1]; step = argv[3]; /* Check size bit (bit 7 of step, 1 = word, 0 = byte) */ if (step & 0x80) { step &= 0x7f; /* Scan down an array for count words looking for a match */ for (i = 0; i < argv[2]; i++) { /* If the word was found store its address and jump */ if (read_data_word (&address) == argv[0]) { store_operand ((zword_t) (address - 2)); conditional_jump (TRUE); return; } /* Back up address then step by increment */ address = (address - 2) + step; } } else { step &= 0x7f; /* Scan down an array for count bytes looking for a match */ for (i = 0; i < argv[2]; i++) { /* If the byte was found store its address and jump */ if ((zword_t) read_data_byte (&address) == (zword_t) argv[0]) { store_operand ((zword_t) (address - 1)); conditional_jump (TRUE); return; } /* Back up address then step by increment */ address = (address - 1) + step; } } /* If the data was not found store zero and jump */ store_operand (0); conditional_jump (FALSE); }/* scan_data */ /* * move_data * */ #ifdef __STDC__ void move_data (zword_t src, zword_t dst, zword_t count) #else void move_data (src, dst, count) zword_t src; zword_t dst; zword_t count; #endif { unsigned long address; unsigned int i; /* Catch no-op move case */ if (src == dst || count == 0) return; /* If destination address is zero then fill source with zeros */ if (dst == 0) { for (i = 0; i < count; i++) store_byte (src++, 0, 0); return; } address = src; if ((short) count < 0) { while (count++) store_byte (dst++, 0, read_data_byte (&address)); } else { address += (unsigned long) count; dst += count; while (count--) { address--; store_byte (--dst, 0, read_data_byte (&address)); address--; } } }/* move_data */ /* * load_word * * Load a word from an array of words * */ #ifdef __STDC__ void load_word (zword_t addr, zword_t offset) #else void load_word (addr, offset) zword_t addr; zword_t offset; #endif { unsigned long address; /* Calculate word array index address */ address = addr + (offset * 2); /* Store the byte */ store_operand (read_data_word (&address)); }/* load_word */ /* * load_byte * * Load a byte from an array of bytes * */ #ifdef __STDC__ void load_byte (zword_t addr, zword_t offset) #else void load_byte (addr, offset) zword_t addr; zword_t offset; #endif { unsigned long address; /* Calculate byte array index address */ address = addr + offset; /* Load the byte */ store_operand (read_data_byte (&address)); }/* load_byte */ /* * store_word * * Store a word in an array of words * */ #ifdef __STDC__ void store_word (zword_t addr, zword_t offset, zword_t value) #else void store_word (addr, offset, value) zword_t addr; zword_t offset; zword_t value; #endif { /* Calculate word array index address */ addr += offset * 2; /* Check we are not writing outside of the writeable data area */ if (addr > data_size) fatal ("Attempted write out of data area"); /* Store the word */ set_word (addr, value); }/* store_word */ /* * store_byte * * Store a byte in an array of bytes * */ #ifdef __STDC__ void store_byte (zword_t addr, zword_t offset, zword_t value) #else void store_byte (addr, offset, value) zword_t addr; zword_t offset; zword_t value; #endif { /* Calculate byte array index address */ addr += offset; /* Check we are not writing outside of the writeable data area */ if (addr > data_size) fatal ("Attempted write out of data area"); /* Store the byte */ set_byte (addr, value); }/* store_byte */ xzip/screen.c0100600000076400007640000003072106706746466012212 0ustar zarfzarf/* * screen.c * * Generic screen manipulation routines. Most of these routines call the machine * specific routines to do the actual work. * */ #include "ztypes.h" /* * select_window * * Put the cursor in the text or status window. The cursor is free to move in * the status window, but is fixed to the input line in the text window. * */ #ifdef __STDC__ void select_window (zword_t w) #else void select_window (w) zword_t w; #endif { int row, col; flush_buffer (FALSE); screen_window = w; if (screen_window == STATUS_WINDOW) { /* Status window: disable formatting and select status window */ formatting = OFF; scripting_disable = ON; select_status_window (); /* Put cursor at top of status area */ if (h_type < V4) move_cursor (2, 1); else move_cursor (1, 1); } else { /* Text window: enable formatting and select text window */ select_text_window (); scripting_disable = OFF; formatting = ON; /* Move cursor if it has been left in the status area */ /*get_cursor_position (&row, &col); if (row <= status_size) move_cursor (status_size + 1, 1);*/ } /* Force text attribute to normal rendition */ set_attribute (NORMAL); }/* select_window */ /* * set_status_size * * Set the size of the status window. The default size for the status window is * zero lines for both type 3 and 4 games. The status line is handled specially * for type 3 games and always occurs the line immediately above the status * window. * */ #ifdef __STDC__ void set_status_size (zword_t lines) #else void set_status_size (lines) zword_t lines; #endif { /* Maximum status window size is 255 */ lines &= 0xff; /* The top line is always set for V1 to V3 games, so account for it here. */ if (h_type < V4) lines++; if (lines) { /* If size is non zero the turn on the status window */ status_active = ON; /* Bound the status size to one line less than the total screen height */ if (lines > (zword_t) (screen_rows - 1)) status_size = (zword_t) (screen_rows - 1); else status_size = lines; /* Create the status window, or resize it */ create_status_window (lines); /* Need to clear the status window for type 3 games */ if (h_type < V4) erase_window (STATUS_WINDOW); } else { /* Lines are zero so turn off the status window */ status_active = OFF; /* Reset the lines written counter and status size */ lines_written = 0; status_size = 0; /* Delete the status window */ delete_status_window (); /* Return cursor to text window */ select_text_window (); } }/* set_status_size */ /* * erase_window * * Clear one or all windows on the screen. * */ #ifdef __STDC__ void erase_window (zword_t w) #else void erase_window (w) zword_t w; #endif { flush_buffer (TRUE); if ((zbyte_t) w == (zbyte_t) SCREEN) { clear_screen (); } else if ((zbyte_t) w == TEXT_WINDOW) { clear_text_window (); } else if ((zbyte_t) w == STATUS_WINDOW) { clear_status_window (); return; } if (h_type > V4) move_cursor (1, 1); else move_cursor (screen_rows, 1); }/* erase_window */ /* * erase_line * * Clear one line on the screen. * */ #ifdef __STDC__ void erase_line (zword_t flag) #else void erase_line (flag) zword_t flag; #endif { if (flag == TRUE) clear_line (); }/* erase_line */ /* * set_cursor_position * * Set the cursor position in the status window only. * */ #ifdef __STDC__ void set_cursor_position (zword_t row, zword_t column) #else void set_cursor_position (row, column) zword_t row; zword_t column; #endif { /* Can only move cursor if format mode is off and in status window */ if (formatting == OFF && screen_window == STATUS_WINDOW) move_cursor (row, column); }/* set_cursor_position */ /* * pad_line * * Pad the status line with spaces up to a column position. * */ #ifdef __STDC__ static void pad_line (int column) #else static void pad_line (column) int column; #endif { int i; for (i = status_pos; i < column; i++) write_char (' '); status_pos = column; }/* pad_line */ /* * display_status_line * * Format and output the status line for type 3 games only. * */ #ifdef __STDC__ void display_status_line (void) #else void display_status_line () #endif { int i, count = 0, end_of_string[3]; char *status_part[3]; /* Move the cursor to the top line of the status window, set the reverse rendition and print the status line */ select_window (STATUS_WINDOW); move_cursor (1, 1); set_attribute (REVERSE); /* Redirect output to the status line buffer */ set_print_modes (3, 0); /* Print the object description for global variable 16 */ pad_line (1); status_part[count] = &status_line[status_pos]; if (load_variable (16) != 0) print_object (load_variable (16)); end_of_string[count++] = status_pos; status_line[status_pos++] = '\0'; if (get_byte (H_CONFIG) & CONFIG_TIME) { /* If a time display print the hours and minutes from global variables 17 and 18 */ pad_line (screen_cols - 21); status_part[count] = &status_line[status_pos]; write_string (" Time: "); print_time (load_variable (17), load_variable (18)); end_of_string[count++] = status_pos; status_line[status_pos++] = '\0'; } else { /* If a moves/score display print the score and moves from global variables 17 and 18 */ pad_line (screen_cols - 31); status_part[count] = &status_line[status_pos]; write_string (" Score: "); print_number (load_variable (17)); end_of_string[count++] = status_pos; status_line[status_pos++] = '\0'; pad_line (screen_cols - 15); status_part[count] = &status_line[status_pos]; write_string (" Moves: "); print_number (load_variable (18)); end_of_string[count++] = status_pos; status_line[status_pos++] = '\0'; } /* Pad the end of status line with spaces then disable output redirection */ pad_line (screen_cols); set_print_modes ((zword_t) -3, 0); /* Try and print the status line for a proportional font screen. If this fails then remove embedded nulls in status line buffer and just output it to the screen */ if (print_status (count, status_part) == FALSE) { for (i = 0; i < count; i++) status_line[end_of_string[i]] = ' '; status_line[status_pos] = '\0'; write_string (status_line); } set_attribute (NORMAL); select_window (TEXT_WINDOW); }/* display_status_line */ /* * blank_status_line * * Output a blank status line for type 3 games only. * */ #ifdef __STDC__ void blank_status_line (void) #else void blank_status_line () #endif { /* Move the cursor to the top line of the status window, set the reverse rendition and print the status line */ select_window (STATUS_WINDOW); move_cursor (1, 1); set_attribute (REVERSE); /* Redirect output to the status line buffer and pad the status line with spaces then disable output redirection */ set_print_modes (3, 0); pad_line (screen_cols); status_line[status_pos] = '\0'; set_print_modes ((zword_t) -3, 0); /* Write the status line */ write_string (status_line); /* Turn off attributes and return to text window */ set_attribute (NORMAL); select_window (TEXT_WINDOW); }/* blank_status_line */ /* * output_string * * Output a string of characters. * */ #ifdef __STDC__ void output_string (const char *s) #else void output_string (s) const char *s; #endif { while (*s) output_char (*s++); }/* output_string */ /* * output_line * * Output a string of characters followed by a new line. * */ #ifdef __STDC__ void output_line (const char *s) #else void output_line (s) const char *s; #endif { output_string (s); output_new_line (); }/* output_line */ /* * output_char * * Output a character and rendition selection. This routine also handles * selecting rendition attributes such as bolding and reverse. There are * five attributes distinguished by a bit mask. 0 means turn all attributes * off. The attributes are: 1 = reverse, 2 = bold, 4 = emphasis, and * 8 = fixed font. * */ #ifdef __STDC__ void output_char (int c) #else void output_char (c) int c; #endif { /* If output is enabled then either select the rendition attribute or just display the character */ if (outputting == ON) { /* Make sure we are dealing with a positive integer */ c = (unsigned int) (c & 0xff); /* Attribute selection. We have to check the force-fixed flag, because the game can set it at whim. */ { static int forcefix = (-1); int currentfix = (get_word (H_FLAGS) & FIXED_FONT_FLAG); if (forcefix != currentfix) { forcefix = currentfix; /* tickle the display attribute so it notices the changed flag */ set_attribute(NO_CHANGE_ATTRIBUTE); } } if (c >= (MIN_ATTRIBUTE + 1) && c <= (MAX_ATTRIBUTE + 1)) { set_attribute (--c); } else { display_char (c); } } }/* output_char */ /* * output_new_line * * Scroll the text window up one line and pause the window if it is full. * */ #ifdef __STDC__ void output_new_line (void) #else void output_new_line () #endif { int row, col; /* Don't print if output is disabled or replaying commands */ if (outputting == ON) { if (formatting == ON && screen_window == TEXT_WINDOW) { /* If this is the text window then scroll it up one line */ scroll_line (); /* paging ain't done here any more. --zarf */ } else /* If this is the status window then just output a new line */ output_char ('\n'); } }/* output_new_line */ /* * print_window * * Writes text into a rectangular window on the screen. * * argv[0] = start of text address * argv[1] = rectangle width * argv[2] = rectangle height (default = 1) * */ #ifdef __STDC__ void print_window (int argc, zword_t *argv) #else void print_window (argc, argv) int argc; zword_t *argv; #endif { unsigned long address; unsigned int width, height; unsigned int row, column; /* Supply default arguments */ if (argc < 3) argv[2] = 1; /* Don't do anything if the window is zero high or wide */ if (argv[1] == 0 || argv[2] == 0) return; /* Get coordinates of top left corner of rectangle */ get_cursor_position ((int *) &row, (int *) &column); address = argv[0]; /* Write text in width * height rectangle */ for (height = 0; height < argv[2]; height++) { for (width = 0; width < argv[1]; width++) write_char (read_data_byte (&address)); /* Put cursor back to lefthand side of rectangle on next line */ if (height != (argv[2] - 1)) move_cursor (++row, column); } }/* print_window */ /* * set_font_attribute * * Set text or graphic font. 1 = text font, 3 = graphics font. * */ #ifdef __STDC__ void set_font_attribute (zword_t new_font) #else void set_font_attribute (new_font) zword_t new_font; #endif { zword_t old_font = font; int res; if (new_font != old_font) { font = new_font; res = set_font (font); if (!res) old_font = 0; } store_operand (old_font); }/* set_font_attribute */ /* * set_colour_attribute * * Set the colour of the screen. Colour can be set on four things: * Screen background * Text typed by player * Text written by game * Graphics characters * * Colors can be set to 1 of 9 values: * 1 = machine default (IBM/PC = blue background, everything else white) * 2 = black * 3 = red * 4 = green * 5 = brown * 6 = blue * 7 = magenta * 8 = cyan * 9 = white * */ #ifdef __STDC__ void set_colour_attribute (zword_t foreground, zword_t background) #else void set_colour_attribute (foreground, background) zword_t foreground; zword_t background; #endif { if (!(foreground >= 0 && foreground <= 9 && background >= 0 && background <= 9)) { fatal ("Bad colour!"); } flush_buffer (FALSE); set_colours (foreground, background); return; }/* set_colour_attribute */ xzip/input.c0100600000076400007640000003405206551763103012054 0ustar zarfzarf/* * input.c * * Input routines * */ #include "ztypes.h" /* Statically defined word separator list */ static const char *separators = " \t\n\f.,?"; static zword_t dictionary_offset = 0; static short dictionary_size = 0; static unsigned int entry_size = 0; #ifdef __STDC__ static void tokenise_line (zword_t, zword_t, zword_t, zword_t); static const char *next_token (const char *, const char *, const char **, int *, const char *); static zword_t find_word (int, const char *, long); #else static void tokenise_line (); static const char *next_token (); static zword_t find_word (); #endif /* * read_character * * Read one character with optional timeout * * argv[0] = # of characters to read (only 1 supported currently) * argv[1] = timeout value in seconds (optional) * argv[2] = timeout action routine (optional) * */ #ifdef __STDC__ void read_character (int argc, zword_t *argv) #else void read_character (argc, argv) int argc; zword_t *argv; #endif { int c; zword_t arg_list[2]; /* Supply default parameters */ if (argc < 3) argv[2] = 0; if (argc < 2) argv[1] = 0; /* Flush any buffered output before read */ flush_buffer (FALSE); /* Reset line count */ lines_written = 0; /* If more than one characters was asked for then fail the call */ if (argv[0] != 1) c = 0; else { if ((c = playback_key ()) == -1) { /* Setup the timeout routine argument list */ arg_list[0] = argv[2]; arg_list[1] = argv[1]; /* Read a character with a timeout. If the input timed out then call the timeout action routine. If the return status from the timeout routine was 0 then try to read a character again */ do { c = input_character ((int) argv[1]); } while (c == -1 && call (1, arg_list, ASYNC) == 0); /* Fail call if input timed out */ if (c == -1) c = 0; else record_key (c); } } store_operand (c); }/* read_character */ /* * read_line * * Read a line of input with optional timeout. * * argv[0] = character buffer address * argv[1] = token buffer address * argv[2] = timeout value in seconds (optional) * argv[3] = timeout action routine (optional) * */ #ifdef __STDC__ void read_line (int argc, zword_t *argv) #else void read_line (argc, argv) int argc; zword_t *argv; #endif { int i, in_size, out_size, terminator; char *cbuf, *buffer; /* Supply default parameters */ if (argc < 4) argv[3] = 0; if (argc < 3) argv[2] = 0; if (argc < 2) argv[1] = 0; /* Refresh status line */ if (h_type < V4) display_status_line (); /* Flush any buffered output before read */ flush_buffer (TRUE); /* Reset line count */ lines_written = 0; /* Initialise character pointer and initial read size */ cbuf = (char *) &datap[argv[0]]; in_size = (h_type > V4) ? cbuf[1] : 0; /* Read the line */ terminator = get_line (cbuf, argv[2], argv[3]); if (h_type > V4) { buffer = &cbuf[2]; out_size = (unsigned char)(cbuf[1]); } else { buffer = &cbuf[1]; out_size = strlen (buffer); } /* Then script and record it */ script_line (buffer, out_size); record_line (buffer, out_size); /* Convert new text in line to lowercase */ if (out_size > in_size) for (i = in_size; i < out_size; i++) buffer[i] = (char) tolower (buffer[i]); /* Tokenise the line, if a token buffer is present */ if (argv[1]) tokenise_line (argv[0], argv[1], h_words_offset, 0); /* Return the line terminator */ if (h_type > V4) store_operand ((zword_t) terminator); }/* read_line */ /* * get_line * * Read a line of input and lower case it. * */ #ifdef __STDC__ int get_line (char *cbuf, zword_t timeout, zword_t action_routine) #else int get_line (cbuf, timeout, action_routine) char *cbuf; zword_t timeout; zword_t action_routine; #endif { char *buffer; int buflen, read_size, status, c; zword_t arg_list[2]; /* Set maximum buffer size to width of screen minus any right margin and 1 character for a terminating NULL */ /*buflen = (screen_cols > 127) ? 127 : screen_cols; buflen -= right_margin + 1;*/ buflen = 127; /* --zarf */ if ((unsigned char) cbuf[0] <= buflen) buflen = (unsigned char) cbuf[0]; /* Set read size and start of read buffer. The buffer may already be primed with same text in V5 games. The Z-code will have already displayed the text so we don't have to do that */ if (h_type > V4) { read_size = (unsigned char) cbuf[1]; buffer = &cbuf[2]; } else { read_size = 0; buffer = &cbuf[1]; } /* Try to read input from command file */ c = playback_line (buflen, buffer, &read_size); if (c == -1) { /* Setup the timeout routine argument list */ arg_list[0] = action_routine; arg_list[1] = timeout; /* Read a line with a timeout. If the input timed out then call the timeout action routine. If the return status from the timeout routine was 0 then try to read the line again */ status = 1; do { c = input_line (buflen, buffer, timeout, &read_size, status); status = 0; } while (c == -1 && (status = call (1, arg_list, ASYNC)) == 0); /* Throw away any input if timeout returns success */ if (status) read_size = 0; } if (h_type > V4) { cbuf[1] = (char) read_size; } else { /* Zero terminate line (V1-4 only) */ buffer[read_size] = '\0'; } return (c); }/* get_line */ /* * tokenise_line * * Convert a typed input line into tokens. The token buffer needs some * additional explanation. The first byte is the maximum number of tokens * allowed. The second byte is set to the actual number of token read. Each * token is composed of 3 fields. The first (word) field contains the word * offset in the dictionary, the second (byte) field contains the token length, * and the third (byte) field contains the start offset of the token in the * character buffer. * */ #ifdef __STDC__ static void tokenise_line (zword_t char_buf, zword_t token_buf, zword_t dictionary, zword_t flag) #else static void tokenise_line (char_buf, token_buf, dictionary, flag) zword_t char_buf; zword_t token_buf; zword_t dictionary; zword_t flag; #endif { int i, count, words, token_length; long word_index, chop = 0; int slen; char *str_end; char *cbuf, *tbuf, *tp; const char *cp, *token; char punctuation[16]; zword_t word; /* Initialise character and token buffer pointers */ cbuf = (char *) &datap[char_buf]; tbuf = (char *) &datap[token_buf]; /* Find the string length */ if (h_type > V4) { slen = (unsigned char)(cbuf[1]); str_end = cbuf + 2 + slen; } else { slen = strlen(cbuf+1); str_end = cbuf + 1 + slen; } /* Initialise word count and pointers */ words = 0; cp = (h_type > V4) ? cbuf + 2 : cbuf + 1; tp = tbuf + 2; /* Initialise dictionary */ count = get_byte (dictionary++); for (i = 0; i < count; i++) punctuation[i] = get_byte (dictionary++); punctuation[i] = '\0'; entry_size = get_byte (dictionary++); dictionary_size = (short) get_word (dictionary); dictionary_offset = dictionary + 2; /* Calculate the binary chop start position */ if (dictionary_size > 0) { word_index = dictionary_size / 2; chop = 1; do chop *= 2; while (word_index /= 2); } /* Tokenise the line */ do { /* Skip to next token */ cp = next_token (cp, str_end, &token, &token_length, punctuation); if (token_length) /* If still space in token buffer then store word */ if (words <= tbuf[0]) { /* Get the word offset from the dictionary */ word = find_word (token_length, token, chop); /* Store the dictionary offset, token length and offset */ if (word || flag == 0) { tp[0] = (char) (word >> 8); tp[1] = (char) (word & 0xff); } tp[2] = (char) token_length; tp[3] = (char) (token - cbuf); /* Step to next token position and count the word */ tp += 4; words++; } else { /* Moan if token buffer space exhausted */ output_string ("Too many words typed, discarding: "); output_line (token); } } while (token_length); /* Store word count */ tbuf[1] = (char) words; }/* tokenise_line */ /* * next_token * * Find next token in a string. The token (word) is delimited by a statically * defined and a game specific set of word separators. The game specific set * of separators look like real word separators, but the parser wants to know * about them. An example would be: 'grue, take the axe. go north'. The * parser wants to know about the comma and the period so that it can correctly * parse the line. The 'interesting' word separators normally appear at the * start of the dictionary, and are also put in a separate list in the game * file. * */ #ifdef __STDC__ static const char *next_token (const char *s, const char *str_end, const char **token, int *length, const char *punctuation) #else static const char *next_token (s, str_end, token, length, punctuation) const char *s; const char *str_end; const char **token; int *length; const char *punctuation; #endif { int i; /* Set the token length to zero */ *length = 0; /* Step through the string looking for separators */ for (; s < str_end; s++) { /* Look for game specific word separators first */ for (i = 0; punctuation[i] && *s != punctuation[i]; i++) ; /* If a separator is found then return the information */ if (punctuation[i]) { /* If length has been set then just return the word position */ if (*length) return (s); else { /* End of word, so set length, token pointer and return string */ (*length)++; *token = s; return (++s); } } /* Look for statically defined separators last */ for (i = 0; separators[i] && *s != separators[i]; i++) ; /* If a separator is found then return the information */ if (separators[i]) { /* If length has been set then just return the word position */ if (*length) return (++s); } else { /* If first token character then remember its position */ if (*length == 0) *token = s; (*length)++; } } return (s); }/* next_token */ /* * find_word * * Search the dictionary for a word. Just encode the word and binary chop the * dictionary looking for it. * */ #ifdef __STDC__ static zword_t find_word (int len, const char *cp, long chop) #else static zword_t find_word (len, cp, chop) int len; const char *cp; long chop; #endif { short int word[3]; long word_index, offset, status; /* Don't look up the word if there are no dictionary entries */ if (dictionary_size == 0) return (0); /* Encode target word */ encode_text (len, cp, word); /* Do a binary chop search on the main dictionary, otherwise do a linear search */ word_index = chop - 1; if (dictionary_size > 0) { /* Binary chop until the word is found */ while (chop) { chop /= 2; /* Calculate dictionary offset */ if (word_index > (dictionary_size - 1)) word_index = dictionary_size - 1; offset = dictionary_offset + (word_index * entry_size); /* If word matches then return dictionary offset */ if ((status = word[0] - (short) get_word (offset + 0)) == 0 && (status = word[1] - (short) get_word (offset + 2)) == 0 && (h_type < V4 || (status = word[2] - (short) get_word (offset + 4)) == 0)) return ((zword_t) offset); /* Set next position depending on direction of overshoot */ if (status > 0) { word_index += chop; /* Deal with end of dictionary case */ if (word_index >= (int) dictionary_size) word_index = dictionary_size - 1; } else { word_index -= chop; /* Deal with start of dictionary case */ if (word_index < 0) word_index = 0; } } } else { for (word_index = 0; word_index < -dictionary_size; word_index++) { /* Calculate dictionary offset */ offset = dictionary_offset + (word_index * entry_size); /* If word matches then return dictionary offset */ if ((status = word[0] - (short) get_word (offset + 0)) == 0 && (status = word[1] - (short) get_word (offset + 2)) == 0 && (h_type < V4 || (status = word[2] - (short) get_word (offset + 4)) == 0)) return ((zword_t) offset); } } return (0); }/* find_word */ /* * tokenise * * argv[0] = character buffer address * argv[1] = token buffer address * argv[2] = alternate vocabulary table * argv[3] = ignore unknown words flag * */ #ifdef __STDC__ void tokenise (int argc, zword_t *argv) #else void tokenise (argc, argv) int argc; zword_t *argv; #endif { /* Supply default parameters */ if (argc < 4) argv[3] = 0; if (argc < 3) argv[2] = h_words_offset; /* Convert the line to tokens */ tokenise_line (argv[0], argv[1], argv[2], argv[3]); }/* tokenise */ xzip/version.h0100600000076400007640000000007107173465504012406 0ustar zarfzarf#define PROGRAMNAME "xzip" #define XZIPVERSION "1.8.2" xzip/README0100600000076400007640000001050707173503014011422 0ustar zarfzarfXZip version 1.8.2 by Andrew Plotkin (erkyrath@eblong.com) based on ZIP V2.0.7 by Mark Howell (howell_ma@movies.enet.dec.com) web site: http://www.eblong.com/zarf/xzip.html This is set up for a fairly generic ANSI C compiler. If you get it to compile under some particular system, please send me mail, and I'll stick in the relevant #ifdefs and whatnot. You MUST define either BIG_END_MODE, LITTLE_END_MODE, or AUTO_END_MODE, by uncommenting one of the lines in the Makefile. If you don't know which is right, try one and see if the program runs right. The error messages are nice and obvious. The AUTO_END_MODE checks a BYTE_ORDER definition which is in the system headers of *some* Unixes. If Murphy's Law strikes, go back to BIG_END_MODE or LITTLE_END_MODE. If your compiler can't find X11 headers or libraries, change the definitions of XLIB and XINCLUDE in the Makefile. There are some sample values there. If you find other values that work on particular operating systems, send me email. If you get errors in xio.c about fd_set or FD_SET being undefined, put "-DNEEDS_SELECT_H" in the SYSTEMFLAGS line, as has been done for the RS6000. If you get errors about bcopy being undefined, put "-DNO_BCOPY" in the SYSTEMFLAGS line. If you get errors about random or srandom being undefined, put "-DLOUSY_RANDOM" in the SYSTEMFLAGS line. If you set DESTDIR to the directory you want things installed in, you can just type "make install". That also installs the man page. Otherwise, "make" or "make xzip" will just build the executable. The FONTDEF_XXX definitions are the fonts used by the various attributes in the interpreter. As you see, they must be delimited by " (double-quotes). If the supplied fonts aren't on your system, pick some that are. All the fonts should look the same size. (I use 14-point Times and 12-point Courier because they look better together than same-size Times and Courier.) Version history: 1.8.2: Added the -spec option, to make the interpreter label itself as spec 1.0 compliant Fixed small bugs in arithmetic shift right and printing newlines. Added support for 64-byte-long properties (spec 1.0 feature) 1.8.1: Fixed the scripton_flag bug (control.c wouldn't compile with a pre-ANSI C compiler) The keypad page-up and page-down keys now work, for those keyboards that have such things. Fixed a bug which could cause a crash on exit. Fixed the set_font opcode to follow the current Z-Spec, and return 0 if the font is not available. 1.8: Added extended save and restore opcodes. Added support for the portable Quetzal save file format. Yes, the save format is changing again. If you don't want this, comment out the definition of "USE_QUETZAL" in the ztypes.h file. Added nested output streams, as described in Z-Spec 1.0. Arrow keys now work right. Fixed bug in scripting (garbage appearing after command inputs) 1.7: Added the -strictz option for better z-code error checking. Fixed bugs in @tokenise whch were causing "You don't see that here" messages. Fixed a problem with color opcodes halting the interpreter. 1.6.1: Made the timed-input code work right. (How embarrassing.) Set all the header bits right. 1.6: Made the division/modulo code more portable. Put in support for more Unixes. Put in support for INFOCOM_PATH environment variable. 1.5: Changed the save file format to be machine-independent (and compatible with JZip.) This means that *this version will not read save files created with XZip 1.4*, if you are on a little-endian machine. Added support for international / accented characters. Fixed bug in signed division and modulo operations. Added PICKLE support, not that anyone cares. 1.4: Added support for the new V8 Z-code format. Fixed a bug in the display of reverse-video text (especially in sections of whitespace which contained both reverse and normal fonts.) 1.3: Added support for fixed-width sections of text. (This was supposed to work already, but the z-machine doesn't work like I thought it did. Sigh.) Also fixed small scrolling bug. 1.2: Improved support for timed input (a la Border Zone) and input in the status window (a la Bureacracy). Added macros and the explain-key function. 1.1: It now reads command-line options as well as X resources. Changed name of random() function to ziprandom(), to avoid conflict with the standard random(). Added __STDC__ conditionals to support non-ANSI compilers. 1.0: Initial release. xzip/ztypes.h0100600000076400007640000004707707173500174012271 0ustar zarfzarf/* * ztypes.h * * Any global stuff required by the C modules. * */ #if !defined(__ZTYPES_INCLUDED) #define __ZTYPES_INCLUDED #include #include #include #include #include #include #if defined(MSDOS) #include #endif /* MSDOS */ /* Try the endianness auto-detect. */ #ifdef AUTO_END_MODE #ifdef BYTE_ORDER #if BYTE_ORDER == BIG_ENDIAN #define BIG_END_MODE #endif #if BYTE_ORDER == LITTLE_ENDIAN #define LITTLE_END_MODE #endif #endif /* BYTE_ORDER */ #endif /* AUTO_END_MODE */ /* Define bcopy() if necessary. */ #ifdef NO_BCOPY #define bcopy(s1,s2,l) (memcpy((s2),(s1),(l))) #endif /* NO_BCOPY */ /* Define which random functions we're gonna use. */ #ifdef LOUSY_RANDOM #define RANDOM_FUNC rand #define SRANDOM_FUNC srand #else #define RANDOM_FUNC random #define SRANDOM_FUNC srandom #endif /* Configuration options */ #define DEFAULT_ROWS 24 /* Default screen height */ #define DEFAULT_COLS 80 /* Deafult screen width */ /* Use the Quetzal save file format. This format is portable to other interpreters, and is much smaller than standard save files. However, it is not compatible with standard save files. So if you start using a version of XZip with USE_QUETZAL compiled in, all your old save files will stop working. */ #define USE_QUETZAL /* Perform stricter z-code error checking. If STRICTZ is #defined, the interpreter will check for common opcode errors, such as reading or writing properties of the "nothing" (0) object. When such an error occurs, the opcode will call report_zstrict_error() and then continue in some safe manner. This may mean doing nothing, returning 0, or something like that. See osdepend.c for the definition of report_zstrict_error(). Note that this function may call fatal() to shut down the interpreter. If STRICTZ is not #defined, the STRICTZ patch has no effect at all. It does not even check to continue safely when an error occurs; it just behaves the way ZIP has always behaved. This typically means calling get_property_addr(0) or get_object_address(0), which will return a meaningless value, and continuing on with that. */ #define STRICTZ /* Global defines */ #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #ifndef FILENAME_MAX #define FILENAME_MAX 255 #endif #ifndef EXIT_SUCCESS #define EXIT_SUCCESS 0 #endif #ifndef EXIT_FAILURE #define EXIT_FAILURE 1 #endif #ifndef SEEK_SET #define SEEK_SET 0 #endif #ifndef SEEK_END #define SEEK_END 2 #endif #ifdef unix #define strchr(a, b) index (a, b) #define memmove(a, b, c) bcopy (b, a, c) #define const #endif /* unix */ /* Z types */ typedef unsigned char zbyte_t; /* unsigned 1 byte quantity */ typedef unsigned short zword_t; /* unsigned 2 byte quantity */ /* Data file header format */ typedef struct zheader { zbyte_t type; zbyte_t config; zword_t version; zword_t data_size; zword_t start_pc; zword_t words_offset; zword_t objects_offset; zword_t globals_offset; zword_t restart_size; zword_t flags; zbyte_t release_date[6]; zword_t synonyms_offset; zword_t file_size; zword_t checksum; zbyte_t interpreter; zbyte_t interpreter_version; zbyte_t screen_rows; zbyte_t screen_columns; zbyte_t screen_left; zbyte_t screen_right; zbyte_t screen_top; zbyte_t screen_bottom; zbyte_t max_char_width; zbyte_t max_char_height; zword_t filler1[3]; zword_t function_keys_offset; zword_t filler2[2]; zword_t alternate_alphabet_offset; zword_t mouse_position_offset; zword_t filler3[4]; } zheader_t; #define H_TYPE 0 #define H_CONFIG 1 #define CONFIG_BYTE_SWAPPED 0x01 /* Game data is byte swapped - V3/V4 */ #define CONFIG_COLOUR 0x01 /* Game supports colour - V5+ */ #define CONFIG_TIME 0x02 /* Status line displays time - V3 */ #define CONFIG_MAX_DATA 0x04 /* Data area should 64K if possible - V4+ */ #define CONFIG_TANDY 0x08 /* Tandy licensed game - V3 */ #define CONFIG_EMPHASIS 0x08 /* Interpreter supports text emphasis - V4+ */ #define CONFIG_NOSTATUSLINE 0x10 /* Interpreter cannot support a status line */ #define CONFIG_WINDOWS 0x20 /* Interpreter supports split screen mode */ #define CONFIG_TIMEDINPUT 0x80 /* Interpreter supports timed input - V5 */ #define H_VERSION 2 #define H_DATA_SIZE 4 #define H_START_PC 6 #define H_WORDS_OFFSET 8 #define H_OBJECTS_OFFSET 10 #define H_GLOBALS_OFFSET 12 #define H_RESTART_SIZE 14 #define H_FLAGS 16 #define SCRIPTING_FLAG 0x01 #define FIXED_FONT_FLAG 0x02 #define REFRESH_FLAG 0x04 #define GRAPHICS_FLAG 0x08 #define SOUND_FLAG 0x10 /* V4 */ #define UNDO_AVAILABLE_FLAG 0x10 /* V5 */ #define COLOUR_FLAG 0x40 #define NEW_SOUND_FLAG 0x80 #define H_RELEASE_DATE 18 #define H_SYNONYMS_OFFSET 24 #define H_FILE_SIZE 26 #define H_CHECKSUM 28 #define H_INTERPRETER 30 #define INTERP_GENERIC 0 #define INTERP_DEC_20 1 #define INTERP_APPLE_IIE 2 #define INTERP_MACINTOSH 3 #define INTERP_AMIGA 4 #define INTERP_ATARI_ST 5 #define INTERP_MSDOS 6 #define INTERP_CBM_128 7 #define INTERP_CBM_64 8 #define INTERP_APPLE_IIC 9 #define INTERP_APPLE_IIGS 10 #define INTERP_TANDY 11 #define H_INTERPRETER_VERSION 31 #define H_SCREEN_ROWS 32 #define H_SCREEN_COLUMNS 33 #define H_SCREEN_LEFT 34 #define H_SCREEN_RIGHT 35 #define H_SCREEN_TOP 36 #define H_SCREEN_BOTTOM 37 #define H_MAX_CHAR_WIDTH 38 #define H_MAX_CHAR_HEIGHT 39 #define H_FILLER1 40 #define H_FUNCTION_KEYS_OFFSET 46 #define H_FILLER2 48 #define H_ALTERNATE_ALPHABET_OFFSET 52 #define H_MOUSE_POSITION_OFFSET 54 #define H_FILLER3 56 #define V1 1 #define V2 2 /* Version 3 object format */ #define V3 3 typedef struct zobjectv3 { zword_t attributes[2]; zbyte_t parent; zbyte_t next; zbyte_t child; zword_t property_offset; } zobjectv3_t; #define O3_ATTRIBUTES 0 #define O3_PARENT 4 #define O3_NEXT 5 #define O3_CHILD 6 #define O3_PROPERTY_OFFSET 7 #define O3_SIZE 9 #define PARENT3(offset) (offset + O3_PARENT) #define NEXT3(offset) (offset + O3_NEXT) #define CHILD3(offset) (offset + O3_CHILD) #define P3_MAX_PROPERTIES 0x20 /* Version 4 object format */ #define V4 4 typedef struct zobjectv4 { zword_t attributes[3]; zword_t parent; zword_t next; zword_t child; zword_t property_offset; } zobjectv4_t; #define O4_ATTRIBUTES 0 #define O4_PARENT 6 #define O4_NEXT 8 #define O4_CHILD 10 #define O4_PROPERTY_OFFSET 12 #define O4_SIZE 14 #define PARENT4(offset) (offset + O4_PARENT) #define NEXT4(offset) (offset + O4_NEXT) #define CHILD4(offset) (offset + O4_CHILD) #define P4_MAX_PROPERTIES 0x40 #define V5 5 #define V8 8 /* Interpreter states */ #define STOP 0 #define RUN 1 /* Call types */ #define FUNCTION 0x0000 #define PROCEDURE 0x1000 #define ASYNC 0x2000 #define ARGS_MASK 0x00FF #define VARS_MASK 0x0F00 #define TYPE_MASK 0xF000 #define VAR_SHIFT 8 /* Local defines */ #ifdef PAGE_SIZE /* some systems have PAGE_SIZE defined in sys/limits.h */ #undef PAGE_SIZE #endif #define PAGE_SIZE 0x200 #define PAGE_MASK 0x1FF #define PAGE_SHIFT 9 #define STACK_SIZE 1024 #define ON 1 #define OFF 0 #define RESET -1 #define SCREEN 255 #define TEXT_WINDOW 0 #define STATUS_WINDOW 1 #define NO_CHANGE_ATTRIBUTE (-1) #define MIN_ATTRIBUTE 0 #define NORMAL 0 #define REVERSE 1 #define BOLD 2 #define EMPHASIS 4 #define FIXED_FONT 8 #define MAX_ATTRIBUTE 8 #define NUMFONTS (16) /* convenient --zarf */ #define TEXT_FONT 1 #define GRAPHICS_FONT 3 #define FOREGROUND 0 #define BACKGROUND 1 #define GAME_RESTORE 0 #define GAME_SAVE 1 #define GAME_SCRIPT 2 #define GAME_RECORD 3 #define GAME_PLAYBACK 4 #define UNDO_SAVE 5 #define UNDO_RESTORE 6 #define GAME_SAVEDATA 7 #define GAME_RESTOREDATA 8 #define MAX_TEXT_SIZE 8 /* Data access macros */ #define get_byte(offset) ((zbyte_t) datap[offset]) #define get_word(offset) ((zword_t) (((zword_t) datap[offset] << 8) + (zword_t) datap[offset + 1])) #define set_byte(offset,value) datap[offset] = (zbyte_t) (value) #define set_word(offset,value) datap[offset] = (zbyte_t) ((zword_t) (value) >> 8), datap[offset + 1] = (zbyte_t) ((zword_t) (value) & 0xff) /* External data */ extern zbyte_t h_type; extern zbyte_t h_config; extern zword_t h_version; extern zword_t h_data_size; extern zword_t h_start_pc; extern zword_t h_words_offset; extern zword_t h_objects_offset; extern zword_t h_globals_offset; extern zword_t h_restart_size; extern zword_t h_flags; extern zword_t h_synonyms_offset; extern zword_t h_file_size; extern zword_t h_checksum; extern zbyte_t h_interpreter; extern zbyte_t h_interpreter_version; extern zword_t h_alternate_alphabet_offset; extern int story_scaler; extern int story_shift; extern int property_mask; extern int property_size_mask; extern zword_t stack[STACK_SIZE]; extern zword_t sp; extern zword_t fp; extern zword_t frame_count; extern unsigned long pc; extern int interpreter_state; extern int interpreter_status; extern unsigned int data_size; extern zbyte_t *datap; extern zbyte_t *undo_datap; extern int screen_rows; extern int screen_cols; extern int screen_window; extern int formatting; extern int outputting; extern int redirect_depth; extern int scripting; extern int scripting_disable; extern int recording; extern int replaying; extern int font; extern int status_active; extern int status_size; extern int lines_written; extern int status_pos; /*extern char *line; output buffering is now in xtext.c --zarf */ extern char *status_line; extern char lookup_table[3][26]; extern int strictz_declare_spec; #ifdef STRICTZ /* Definitions for STRICTZ functions and error codes. */ #ifdef __STDC__ void report_strictz_error (int, const char *); #else /* __STDC__ */ void report_strictz_error (); #endif /* __STDC__ */ /* Reporting modes */ extern int strictz_report_mode; #define STRICTZ_REPORT_NEVER (0) #define STRICTZ_REPORT_ONCE (1) #define STRICTZ_REPORT_ALWAYS (2) #define STRICTZ_REPORT_FATAL (3) #define STRICTZ_DEFAULT_REPORT_MODE STRICTZ_REPORT_ONCE /* Error codes */ #define STRZERR_NO_ERROR (0) #define STRZERR_JIN (1) #define STRZERR_GET_CHILD (2) #define STRZERR_GET_PARENT (3) #define STRZERR_GET_SIBLING (4) #define STRZERR_GET_PROP_ADDR (5) #define STRZERR_GET_PROP (6) #define STRZERR_PUT_PROP (7) #define STRZERR_CLEAR_ATTR (8) #define STRZERR_SET_ATTR (9) #define STRZERR_TEST_ATTR (10) #define STRZERR_MOVE_OBJECT (11) #define STRZERR_MOVE_OBJECT_2 (12) #define STRZERR_REMOVE_OBJECT (13) #define STRZERR_GET_NEXT_PROP (14) #define STRICTZ_NUM_ERRORS (15) #endif /* STRICTZ */ /* Global routines */ /* control.c */ #ifdef __STDC__ void check_argument (zword_t); int call (int, zword_t *, int); void get_fp (void); void jump (zword_t); void restart (void); void restart_interp (int scripton_flag); void ret (zword_t); void unwind (zword_t, zword_t); #else void check_argument (); int call (); void get_fp (); void jump (); void restart (); void restart_interp (); void ret (); void unwind (); #endif /* fileio.c */ #ifdef __STDC__ void close_record (void); void close_script (void); void close_story (void); unsigned int get_story_size (void); void open_playback (int); void open_record (void); void open_script (void); void open_story (const char *); int playback_key (void); int playback_line (int, char *, int *); void read_page (int, void *); void record_key (int); void record_line (const char *, int); int restore (int, zword_t *); int save (int, zword_t *); void script_char (int); void script_string (const char *); void script_line (const char *, int); void script_new_line (void); void undo_restore (void); void undo_save (void); void verify (void); #else void close_record (); void close_script (); void close_story (); unsigned int get_story_size (); void open_playback (); void open_record (); void open_script (); void open_story (); int playback_key (); int playback_line (); void read_page (); void record_key (); void record_line (); int restore (); int save (); void script_char (); void script_string (); void script_line (); void script_new_line (); void undo_restore (); void undo_save (); void verify (); #endif /* getopt.c */ /* deleted --zarf */ /* input.c */ #ifdef __STDC__ int get_line (char *, zword_t, zword_t); void read_character (int, zword_t *); void read_line (int, zword_t *); void tokenise (int, zword_t *); #else int get_line (); void read_character (); void read_line (); void tokenise (); #endif /* interpre.c */ #ifdef __STDC__ int interpret (void); #else int interpret (); #endif /* math.c */ #ifdef __STDC__ void add (zword_t, zword_t); void and (zword_t, zword_t); void arith_shift (zword_t, zword_t); void compare_je (int, zword_t *); void compare_jg (zword_t, zword_t); void compare_jl (zword_t, zword_t); void compare_zero (zword_t); void divide (zword_t, zword_t); void multiply (zword_t, zword_t); void not (zword_t); void or (zword_t, zword_t); void ziprandom (zword_t); void remainder (zword_t, zword_t); void shift (zword_t, zword_t); void subtract (zword_t, zword_t); void test (zword_t, zword_t); #else void add (); void and (); void arith_shift (); void compare_je (); void compare_jg (); void compare_jl (); void compare_zero (); void divide (); void multiply (); void not (); void or (); void ziprandom (); void remainder (); void shift (); void subtract (); void test (); #endif /* memory.c */ #ifdef __STDC__ void load_cache (void); void unload_cache (void); zbyte_t read_code_byte (void); zbyte_t read_data_byte (unsigned long *); zword_t read_code_word (void); zword_t read_data_word (unsigned long *); #else void load_cache (); void unload_cache (); zbyte_t read_code_byte (); zbyte_t read_data_byte (); zword_t read_code_word (); zword_t read_data_word (); #endif /* object.c */ #ifdef __STDC__ void clear_attr (zword_t, zword_t); void compare_parent_object (zword_t, zword_t); void insert_object (zword_t, zword_t); void load_child_object (zword_t); void load_next_object (zword_t); void load_parent_object (zword_t); void remove_object (zword_t); void set_attr (zword_t, zword_t); void test_attr (zword_t, zword_t); zword_t get_object_address (zword_t); #else void clear_attr (); void compare_parent_object (); void insert_object (); void load_child_object (); void load_next_object (); void load_parent_object (); void remove_object (); void set_attr (); void test_attr (); zword_t get_object_address (); #endif /* operand.c */ #ifdef __STDC__ void conditional_jump (int); void store_operand (zword_t); void store_variable (int, zword_t); zword_t load_operand (int); zword_t load_variable (int); #else void conditional_jump (); void store_operand (); void store_variable (); zword_t load_operand (); zword_t load_variable (); #endif /* osdepend.c */ #ifdef __STDC__ int codes_to_text (int, char *); void fatal (const char *); void file_cleanup (const char *, int); int fit_line (const char *, int, int); int get_file_name (char *, char *, int); int print_status (int, char *[]); void process_arguments (int, char *[]); void set_colours (int, int); int set_font (int); void sound (int, zword_t *); #else int codes_to_text (); void fatal (); void file_cleanup (); int fit_line (); int get_file_name (); int print_status (); void process_arguments (); void set_colours (); int set_font (); void sound (); #endif /* property.c */ #ifdef __STDC__ void load_byte (zword_t, zword_t); void load_next_property (zword_t, zword_t); void load_property (zword_t, zword_t); void load_property_address (zword_t, zword_t); void load_property_length (zword_t); void load_word (zword_t, zword_t); void move_data (zword_t, zword_t, zword_t); void scan_data (int, zword_t *); void store_byte (zword_t, zword_t, zword_t); void store_property (zword_t, zword_t, zword_t); void store_word (zword_t, zword_t, zword_t); #else void load_byte (); void load_next_property (); void load_property (); void load_property_address (); void load_property_length (); void load_word (); void move_data (); void scan_data (); void store_byte (); void store_property (); void store_word (); #endif /* quetzal.c */ #ifdef __STDC__ int save_quetzal (FILE *, FILE *, long); int restore_quetzal (FILE *, FILE *, long); #else int save_quetzal (); int restore_quetzal (); #endif /* screen.c */ #ifdef __STDC__ void blank_status_line (void); void display_status_line (void); void erase_line (zword_t); void erase_window (zword_t); void output_char (int); void output_new_line (void); void output_string (const char *); void output_line (const char *); void print_window (int, zword_t *); void select_window (zword_t); void set_cursor_position (zword_t, zword_t); void set_colour_attribute (zword_t, zword_t); void set_font_attribute (zword_t); void set_status_size (zword_t); #else void blank_status_line (); void display_status_line (); void erase_line (); void erase_window (); void output_char (); void output_new_line (); void output_string (); void output_line (); void print_window (); void select_window (); void set_cursor_position (); void set_colour_attribute (); void set_font_attribute (); void set_status_size (); #endif /* screenio.c */ #ifdef __STDC__ int input_character (int); void clear_line (void); void clear_screen (void); void clear_status_window (void); void clear_text_window (void); void create_status_window (int); void delete_status_window (void); void display_char (int); int fit_line (const char *, int, int); void get_cursor_position (int *, int *); void initialize_screen (void); int input_line (int, char *, int, int *, int); void move_cursor (int, int); int print_status (int, char *[]); void reset_screen (void); void restart_screen (void); void restore_cursor_position (void); void save_cursor_position (void); void scroll_line (void); void select_status_window (void); void select_text_window (void); void set_attribute (int); #else int input_character (); void clear_line (); void clear_screen (); void clear_status_window (); void clear_text_window (); void create_status_window (); void delete_status_window (); void display_char (); int fit_line (); void get_cursor_position (); void initialize_screen (); int input_line (); void move_cursor (); int print_status (); void reset_screen (); void restart_screen (); void restore_cursor_position (); void save_cursor_position (); void scroll_line (); void select_status_window (); void select_text_window (); void set_attribute (); #endif /* text.c */ #ifdef __STDC__ void decode_text (unsigned long *); void encode (zword_t, zword_t, zword_t, zword_t); void encode_text (int, const char *, short *); void flush_buffer (int); void new_line (void); void print_address (zword_t); void print_character (zword_t); void print_literal (void); void print_number (zword_t); void print_object (zword_t); void print_offset (zword_t); void print_time (int, int); void println_return (void); void command_opcode (zword_t); void set_format_mode (zword_t); void set_print_modes (zword_t, zword_t); void set_video_attribute (zword_t); void write_char (int); void write_string (const char *); void write_zchar (int); #else void decode_text (); void encode (); void encode_text (); void flush_buffer (); void new_line (); void print_address (); void print_character (); void print_literal (); void print_number (); void print_object (); void print_offset (); void print_time (); void println_return (); void command_opcode (); void set_format_mode (); void set_print_modes (); void set_video_attribute (); void write_char (); void write_string (); void write_zchar (); #endif /* variable.c */ #ifdef __STDC__ void decrement (zword_t); void decrement_check (zword_t, zword_t); void increment (zword_t); void increment_check (zword_t, zword_t); void load (zword_t); void pop_var (zword_t); void push_var (zword_t); #else void decrement (); void decrement_check (); void increment (); void increment_check (); void load (); void pop_var (); void push_var (); #endif #endif /* !defined(__ZTYPES_INCLUDED) */ xzip/xio.c0100600000076400007640000005124006551763103011512 0ustar zarfzarf /* initialize_screen() reset_screen() restart_screen() set_attribute(int attr) input_character(int timeout) input_line(int buflen, char *buffer, int timeout, int *read_size) display_char(int ch) clear_line() clear_screen() clear_status_window() clear_text_window() create_status_window(int lines) delete_status_window() get_cursor_position(int *row, int *col) move_cursor(int row, int col) scroll_line() select_status_window() select_text_window() */ #include #ifdef NEEDS_SELECT_H #include #endif #include #include #include #include #include #include "ztypes.h" #include "xio.h" #include "greypm.bm" #define EVENTMASK (ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | KeyPressMask | StructureNotifyMask | ExposureMask) #define STATEVENTMASK (ButtonPressMask | KeyPressMask | StructureNotifyMask | ExposureMask) #define TICKLENGTH (100000) Display *xiodpy; int xioscn; Window xiowin, xioswin; int xiodepth; int xiobackstore; GC gcblack, gcwhite, gcflip, gcgrey; GC gcfont[NUMFONTS]; GC gcsblack, gcsflip; GC gcsfont[NUMFONTS], gcsnegfont[NUMFONTS]; XFontStruct *fontstr[NUMFONTS]; int spacewidth[NUMFONTS]; int lineheight, lineheightoff; preferences prefs; static int screen_inited = FALSE; static int xiowinwid, xiowinhgt; static int statusmode; static int machineattr; static int escapemode = FALSE; static int modifymode = op_Cancel; #ifdef __STDC__ static char *ansicheck = "\nThis binary was compiled with ANSI C.\n"; #else static char *ansicheck = "\nThis binary was compiled with non-ANSI C.\n"; #endif #ifdef __STDC__ static void loop(int stringmode, int *killflag, int timeout); static void eventloop(int stringmode, int *killflag, int timeout); static void redraw(int xpos, int ypos, int wid, int hgt); static void rearrange_window(); #else static void loop(); static void eventloop(); static void redraw(); static void rearrange_window(); #endif #ifdef TESTING static char *wordlist[10] = { "One ", "two ", "three ", "seventeen ", "a ", "veryvery ", "short ", "maybenot ", "I ", "stop. "}; #ifdef __STDC__ main() #else main() #endif { int numl; initialize_screen(); SRANDOM_FUNC(getpid() + time(NULL)); for (numl=0; numl>=0; numl++) { int numwords = RANDOM_FUNC() % 20 + 10; int ix, jx; char *cx; char buf[256]; int pos; pos = 0; input_line(256, buf, 0, &pos); if (pos >= 4 && !strncmp(buf, "quit", 4)) break; for (ix=0; ixfid; gcvalues.foreground = prefs.backcolor; gcvalues.background = prefs.textcolor[ix]; gcsnegfont[ix] = XCreateGC(xiodpy, xioswin, GCForeground|GCBackground|GCFont, &gcvalues); gcvalues.foreground = prefs.textcolor[ix]; gcvalues.background = prefs.backcolor; gcsfont[ix] = XCreateGC(xiodpy, xioswin, GCForeground|GCBackground|GCFont, &gcvalues); } /* --- text window --- */ xiowinwid = prefs.winw; xiowinhgt = prefs.winh; xiowin = XCreateSimpleWindow(xiodpy, DefaultRootWindow(xiodpy), prefs.winx, prefs.winy, xiowinwid, xiowinhgt, 1, prefs.forecolor, prefs.backcolor); { XSizeHints szhints; szhints.flags = PMinSize|USPosition|USSize; szhints.min_width = 250; szhints.min_height = 200; szhints.x = prefs.winx; szhints.y = prefs.winy; szhints.width = xiowinwid; szhints.height = xiowinhgt; XSetNormalHints(xiodpy, xiowin, &szhints); } { /* make some window managers happy */ XWMHints wmhints; wmhints.flags = InputHint; wmhints.input = True; XSetWMHints(xiodpy, xiowin, &wmhints); } attr.event_mask = EVENTMASK; attr.backing_store = WhenMapped; XChangeWindowAttributes(xiodpy, xiowin, CWEventMask|CWBackingStore, &attr); XStoreName(xiodpy, xiowin, "XZip"); XMapWindow(xiodpy, xiowin); gcvalues.function = GXcopy; gcvalues.foreground = prefs.forecolor; gcvalues.background = prefs.backcolor; gcblack = XCreateGC(xiodpy, xiowin, GCForeground|GCBackground, &gcvalues); XSetGraphicsExposures(xiodpy, gcblack, FALSE); gcvalues.foreground = prefs.backcolor; gcvalues.background = prefs.forecolor; gcwhite = XCreateGC(xiodpy, xiowin, GCForeground|GCBackground, &gcvalues); if (xiodepth==1) { gcvalues.fill_style = FillOpaqueStippled; greypm = XCreateBitmapFromData(xiodpy, xiowin, greypm_bits, greypm_width, greypm_height); gcvalues.foreground = prefs.forecolor; gcvalues.background = prefs.backcolor; gcvalues.stipple = greypm; gcgrey = XCreateGC(xiodpy, xiowin, GCForeground|GCBackground|GCFillStyle|GCStipple, &gcvalues); } else { gcvalues.foreground = prefs.greycolor; gcvalues.background = prefs.backcolor; gcgrey = XCreateGC(xiodpy, xiowin, GCForeground|GCBackground, &gcvalues); } gcvalues.function = GXxor; gcvalues.foreground = (prefs.textcolor[0])^(prefs.backcolor); gcvalues.background = (prefs.textcolor[0])^(prefs.backcolor); gcflip = XCreateGC(xiodpy, xiowin, GCFunction|GCForeground|GCBackground, &gcvalues); gcvalues.function = GXcopy; for (ix=0; ixfid; if (ix & REVERSE) { gcvalues.foreground = prefs.backcolor; gcvalues.background = prefs.textcolor[ix]; } else { gcvalues.foreground = prefs.textcolor[ix]; gcvalues.background = prefs.backcolor; } gcfont[ix] = XCreateGC(xiodpy, xiowin, GCForeground|GCBackground|GCFont, &gcvalues); } /* --- final initing */ screen_inited = TRUE; statusmode = FALSE; xtext_init(); xmess_init(); rearrange_window(); { char buf[64]; sprintf(buf, "Welcome to XZip version %s.", XZIPVERSION); xmess_set_message(buf, FALSE); } xstat_init(prefs.statwid, prefs.stathgt, prefs.statwinx, prefs.statwiny); machineattr = NORMAL; } #ifdef __STDC__ void restart_screen() #else void restart_screen() #endif { zbyte_t val; /* H_CONFIG is "flags 1"; H_FLAGS[0,1] is "flags 2". */ switch (h_type) { case V1: case V2: case V3: val = get_byte (H_CONFIG); val |= (0x20 | 0x40); /* screen-splitting, variable-pitch font */ set_byte (H_CONFIG, val); break; case V4: val = get_byte (H_CONFIG); val |= (0x04 | 0x08 | 0x10 | 0x80); /* bold, italic, fixed-width, timed input */ set_byte (H_CONFIG, val); break; case V5: case V8: val = get_byte (H_CONFIG); val |= (0x04 | 0x08 | 0x10 | 0x80); /* bold, italic, fixed-width, timed input */ set_byte (H_CONFIG, val); val = get_byte (H_FLAGS+1); val &= (~0x08); /* no graphics */ val &= (~0x20); /* no mouse */ val &= (~0x80); /* no sound */ set_byte (H_FLAGS+1, val); break; } } #ifdef __STDC__ void reset_screen() #else void reset_screen() #endif { static char *killmessage = "[Hit any key to exit.]"; if (!screen_inited) return; xmess_set_message(killmessage, TRUE); input_character(0); XCloseDisplay(xiodpy); } /* I have extended the definition of this function; a value of -1 does not affect the style, except to re-check the force-fixed bit that the game can set. The original Zip program never called set_attribute with a negative value, so this should be ok. */ #ifdef __STDC__ void set_attribute(int attr) #else void set_attribute(attr) int attr; #endif { int finalattr; if (!attr) machineattr = NORMAL; else if (attr > 0) machineattr |= attr; else { } if (get_word (H_FLAGS) & FIXED_FONT_FLAG) finalattr = machineattr | FIXED_FONT; else finalattr = machineattr; if (!statusmode) { xtext_setstyle(-1, finalattr); } else { xstat_setattr(finalattr); } } #ifdef __STDC__ void clear_line() #else void clear_line() #endif { /* ### do something! */ } /* clear both text and status window */ #ifdef __STDC__ void clear_screen() #else void clear_screen() #endif { xstat_clear_window(); xtext_clear_window(); } #ifdef __STDC__ void clear_status_window() #else void clear_status_window() #endif { xstat_clear_window(); } #ifdef __STDC__ void clear_text_window() #else void clear_text_window() #endif { xtext_clear_window(); } #ifdef __STDC__ void create_status_window(int lines) #else void create_status_window(lines) int lines; #endif { xstat_set_window_size(lines); } #ifdef __STDC__ void delete_status_window() #else void delete_status_window() #endif { xstat_set_window_size(0); } #ifdef __STDC__ void get_cursor_position(int *row, int *col) #else void get_cursor_position(row, col) int *row; int *col; #endif { if (statusmode) { xstat_getpos(row, col); } else { *row = 1; *col = 1; } } #ifdef __STDC__ void move_cursor(int row, int col) #else void move_cursor(row, col) int row; int col; #endif { if (statusmode) { xstat_setpos(row, col); } } #ifdef __STDC__ void scroll_line() #else void scroll_line() #endif { if (statusmode) { /* ### do something? */ } else display_char ('\n'); } #ifdef __STDC__ void select_status_window() #else void select_status_window() #endif { statusmode = TRUE; } #ifdef __STDC__ void select_text_window() #else void select_text_window() #endif { statusmode = FALSE; } #ifdef __STDC__ void xio_bell() #else void xio_bell() #endif { XBell(xiodpy, 0); } #ifdef __STDC__ static void redraw(int xpos, int ypos, int wid, int hgt) #else static void redraw(xpos, ypos, wid, hgt) int xpos; int ypos; int wid; int hgt; #endif { /* yes, we ignore the exposure region. */ XClearWindow(xiodpy, xiowin); xtext_redraw(); xmess_redraw(); } #ifdef __STDC__ static void handlekey(XKeyEvent *event, int stringmode, int *killflag) #else static void handlekey(event, stringmode, killflag) XKeyEvent *event; int stringmode; int *killflag; #endif { int ix; char ch; KeySym ksym; ix = XLookupString(event, &ch, 1, &ksym, NULL); if (IsModifierKey(ksym) || ksym==XK_Multi_key) { return; } /* not yet set up to do keybindings */ if (!stringmode) { if (!ix) { /* ignore non-ascii characters, except arrow keys */ switch (ksym) { case XK_Up: *killflag = 129; break; case XK_Down: *killflag = 130; break; case XK_Left: *killflag = 131; break; case XK_Right: *killflag = 132; break; } return; } switch (ch) { case '\014': /* ctrl-L */ xtexted_redraw(op_AllWindows); break; default: *killflag = (unsigned char)ch; break; } } else { cmdentry *command; int val, which, keynum, op; if (!ix) { val = (ksym & 255); which = keytype_sym; } else { if (escapemode || (event->state & Mod1Mask)) { escapemode = FALSE; val = (ch & 255); which = keytype_meta; } else { val = (ch & 255); which = keytype_main; } } keynum = (val | which); command = keycmds[keynum]; if (modifymode != op_Cancel && !(command && command->ignoremods)) { op = modifymode; modifymode = op_Cancel; xtexted_modify(keynum, op); } else if (!command) { char buf[128]; char *cx; cx = xkey_get_key_name(keynum); sprintf(buf, "Key <%s> not bound", cx); xmess_set_message(buf, FALSE); } else { if (command->operand == (-1)) op = keynum; else op = command->operand; (*(command->func))(op); } } } /* based on new xiowinwid, xiowinhgt */ #ifdef __STDC__ static void rearrange_window() #else static void rearrange_window() #endif { int botwidth = lineheight+3; xtext_resize(0, 0, xiowinwid, xiowinhgt-botwidth); xmess_resize(0, xiowinhgt-botwidth, xiowinwid, botwidth); } /* do one round of iteration -- getchar, getline, whatever is relevant. return -1 after timeout tenth-seconds (if timeout > 0). If stringmode==FALSE, return the first keystroke (immediately). Otherwise, do a line of input using loop_*, returning \n. */ #ifdef __STDC__ static void loop(int stringmode, int *killflag, int timeout) #else static void loop(stringmode, killflag, timeout) int stringmode; int *killflag; int timeout; #endif { xstat_layout(); xtext_layout(); /* the biggie; everything has to be right after this */ xtext_end_visible(); eventloop(stringmode, killflag, timeout); xtext_set_lastseen(); } /* guts of the event loop */ #ifdef __STDC__ static void eventloop(int stringmode, int *killflag, int timeout) #else static void eventloop(stringmode, killflag, timeout) int stringmode; int *killflag; int timeout; #endif { int ix, jx; int eventp; XEvent event; long evmasks; struct timeval tv, curtime, outtime; struct timezone tz; fd_set readbits; static unsigned int buttonhit; static unsigned int buttonmods; static int clicknum; static int lastclickx=(-999), lastclicky=(-999); if (timeout) { gettimeofday (&outtime, &tz); outtime.tv_sec += (timeout/10); outtime.tv_usec += ((timeout%10)*100000); if (outtime.tv_usec >= 1000000) { outtime.tv_sec++; outtime.tv_usec -= 1000000; } } while (1) { evmasks = ~(NoEventMask); eventp = XCheckMaskEvent(xiodpy, evmasks, &event); if (!eventp) { tv.tv_sec = 0; tv.tv_usec = TICKLENGTH; FD_ZERO(&readbits); FD_SET(ConnectionNumber(xiodpy), &readbits); XFlush(xiodpy); select(1+ConnectionNumber(xiodpy), &readbits, 0, 0, &tv); } else if (event.xany.window==xioswin) { switch (event.type) { case ButtonPress: break; case KeyPress: xmess_check_timeout(); handlekey(&event.xkey, stringmode, killflag); break; case ConfigureNotify: xstat_newgeometry(event.xconfigure.x, event.xconfigure.y, event.xconfigure.width, event.xconfigure.height); break; case Expose: do { ix = XCheckWindowEvent(xiodpy, xioswin, ExposureMask, &event); } while (ix); xstat_redraw(); break; } } else { switch (event.type) { case ButtonPress: xmess_check_timeout(); buttonhit = event.xbutton.button; buttonmods = event.xbutton.state; ix = lastclickx-event.xbutton.x; jx = lastclicky-event.xbutton.y; if (ix<=1 && ix>=(-1) && jx<=1 && jx>=(-1)) { clicknum++; } else { clicknum = 1; lastclickx = event.xbutton.x; lastclicky = event.xbutton.y; } xtext_hitdown(event.xbutton.x, event.xbutton.y, buttonhit, buttonmods, clicknum); break; case MotionNotify: xtext_hitmove(event.xbutton.x, event.xbutton.y, buttonhit, buttonmods, clicknum); break; case ButtonRelease: xtext_hitup(event.xbutton.x, event.xbutton.y, buttonhit, buttonmods, clicknum); break; case KeyPress: xmess_check_timeout(); handlekey(&event.xkey, stringmode, killflag); break; case ConfigureNotify: xmess_check_timeout(); if (event.xconfigure.width != xiowinwid || event.xconfigure.height != xiowinhgt) { xiowinwid = event.xconfigure.width; xiowinhgt = event.xconfigure.height; rearrange_window(); } break; case Expose: do { ix = XCheckWindowEvent(xiodpy, xiowin, ExposureMask, &event); } while (ix); redraw(event.xexpose.x, event.xexpose.y, event.xexpose.width, event.xexpose.height); break; default: break; } } if (*killflag != (-1)) { return; } if (timeout) { gettimeofday (&curtime, &tz); if (curtime.tv_sec > outtime.tv_sec || (curtime.tv_sec == outtime.tv_sec && curtime.tv_usec > outtime.tv_usec)) { /* timed out */ *killflag = (-1); return; } } } } #ifdef __STDC__ void xtexted_redraw(int op) #else void xtexted_redraw(op) int op; #endif { switch (op) { case op_Screen: redraw(0, 0, xiowinwid, xiowinhgt); break; case op_Status: xstat_redraw(); break; case op_AllWindows: redraw(0, 0, xiowinwid, xiowinhgt); xstat_redraw(); break; } } #ifdef __STDC__ void xtexted_meta(int op) #else void xtexted_meta(op) int op; #endif { switch (op) { case op_Cancel: escapemode = FALSE; modifymode = op_Cancel; xmess_set_message("Cancelled.", FALSE); break; case op_DefineMacro: xmess_set_message("Type a macro key to redefine.", FALSE); modifymode = op_DefineMacro; break; case op_ExplainKey: xmess_set_message("Type a key to explain.", FALSE); modifymode = op_ExplainKey; break; case op_Escape: escapemode = !escapemode; break; } } #ifdef __STDC__ void xtexted_modify(int keynum, int op) #else void xtexted_modify(keynum, op) int keynum; int op; #endif { char buf[128]; char *cx; cmdentry *command; switch (op) { case op_DefineMacro: xted_define_macro(keynum); break; case op_ExplainKey: cx = xkey_get_key_name(keynum); command = keycmds[keynum]; if (!command) sprintf(buf, "Key <%s> is not bound", cx); else if (!keycmdargs[keynum]) sprintf(buf, "Key <%s>: %s", cx, command->name); else { if (strlen(keycmdargs[keynum]) < sizeof(buf) - 64) sprintf(buf, "Key <%s>: %s \"%s\"", cx, command->name, keycmdargs[keynum]); else { sprintf(buf, "Key <%s>: %s \"", cx, command->name); strncat(buf, keycmdargs[keynum], sizeof(buf) - 64); strcat(buf, "...\""); } } xmess_set_message(buf, FALSE); break; default: sprintf(buf, "Unknown key modifier (%d).", op); xmess_set_message(buf, FALSE); break; } } xzip/osdepend.c0100600000076400007640000004363007173502660012520 0ustar zarfzarf/* * osdepend.c * * All non screen specific operating system dependent routines. * * Olaf Barthel 28-Jul-1992 * */ #include "ztypes.h" #include "arguments.h" #include "version.h" /* File names will be O/S dependent */ #if defined(AMIGA) #define SAVE_NAME "Story.Save" /* Default save name */ #define SCRIPT_NAME "PRT:" /* Default script name */ #define RECORD_NAME "Story.Record" /* Default record name */ #else /* defined(AMIGA) */ #define SAVE_NAME "story.sav" /* Default save name */ #define SCRIPT_NAME "story.lis" /* Default script name */ #define RECORD_NAME "record.lis" /* Default record name */ #endif /* defined(AMIGA) */ static optionname optionnamelist[] = { {"bindings", OPT_BINDINGS, TRUE}, {"strictz", OPT_STRICTZ, TRUE}, {"spec", OPT_SPEC, TRUE}, {"geometry", OPT_GEOMETRY, TRUE}, {"statgeometry", OPT_STATGEOMETRY, TRUE}, {"inputstyle", OPT_INPUTSTYLE, TRUE}, {"marginx", OPT_MARGINX, TRUE}, {"leading", OPT_LEADING, TRUE}, {"justify", OPT_JUSTIFY, TRUE}, {"autoresize", OPT_AUTORESIZE, TRUE}, {"resizeupward", OPT_RESIZEUPWARD, TRUE}, {"autoclear", OPT_AUTOCLEAR, TRUE}, {"history", OPT_HISTORY, TRUE}, {"buffer", OPT_BUFFER, TRUE}, {"background", OPT_BACKGROUND, TRUE}, {"foreground", OPT_FOREGROUND, TRUE}, {"bg", OPT_BACKGROUND, FALSE}, {"fg", OPT_FOREGROUND, FALSE}, {"greycolor", OPT_GREYCOLOR, TRUE}, {"n-color", OPT_STYLECOLOR+0, TRUE}, {"r-color", OPT_STYLECOLOR+1, TRUE}, {"b-color", OPT_STYLECOLOR+2, TRUE}, {"rb-color", OPT_STYLECOLOR+3, TRUE}, {"i-color", OPT_STYLECOLOR+4, TRUE}, {"ri-color", OPT_STYLECOLOR+5, TRUE}, {"bi-color", OPT_STYLECOLOR+6, TRUE}, {"rbi-color", OPT_STYLECOLOR+7, TRUE}, {"f-color", OPT_STYLECOLOR+8, TRUE}, {"rf-color", OPT_STYLECOLOR+9, TRUE}, {"bf-color", OPT_STYLECOLOR+10, TRUE}, {"rbf-color", OPT_STYLECOLOR+11, TRUE}, {"if-color", OPT_STYLECOLOR+12, TRUE}, {"rif-color", OPT_STYLECOLOR+13, TRUE}, {"bif-color", OPT_STYLECOLOR+14, TRUE}, {"rbif-color", OPT_STYLECOLOR+15, TRUE}, {"n-font", OPT_STYLEFONT+0, TRUE}, {"r-font", OPT_STYLEFONT+1, TRUE}, {"b-font", OPT_STYLEFONT+2, TRUE}, {"rb-font", OPT_STYLEFONT+3, TRUE}, {"i-font", OPT_STYLEFONT+4, TRUE}, {"ri-font", OPT_STYLEFONT+5, TRUE}, {"bi-font", OPT_STYLEFONT+6, TRUE}, {"rbi-font", OPT_STYLEFONT+7, TRUE}, {"f-font", OPT_STYLEFONT+8, TRUE}, {"rf-font", OPT_STYLEFONT+9, TRUE}, {"bf-font", OPT_STYLEFONT+10, TRUE}, {"rbf-font", OPT_STYLEFONT+11, TRUE}, {"if-font", OPT_STYLEFONT+12, TRUE}, {"rif-font", OPT_STYLEFONT+13, TRUE}, {"bif-font", OPT_STYLEFONT+14, TRUE}, {"rbif-font", OPT_STYLEFONT+15, TRUE}, {"help", OPT_HELP, TRUE}, {NULL, 0, FALSE} }; unixoption unixoptionlist[NUMOPTIONS]; int strictz_declare_spec; #ifdef STRICTZ /* Define stuff for stricter Z-code error checking, for the generic Unix/DOS/etc terminal-window interface. Feel free to change the way player prefs are specified, or replace report_zstrict_error() completely if you want to change the way errors are reported. */ /* There are four error reporting modes: never report errors; report only the first time a given error type occurs; report every time an error occurs; or treat all errors as fatal errors, killing the interpreter. I strongly recommend "report once" as the default. But you can compile in a different default by changing the definition of STRICTZ_DEFAULT_REPORT_MODE. In any case, the player can specify a report mode on the command line by typing "-s 0" through "-s 3". */ int strictz_report_mode; static int strictz_error_count[STRICTZ_NUM_ERRORS]; #endif /* STRICTZ */ #if !defined(AMIGA) /* * process_arguments * * Do any argument preprocessing necessary before the game is * started. This may include selecting a specific game file or * setting interface-specific options. * */ #ifdef __STDC__ void process_arguments (int argc, char *argv[]) #else void process_arguments (argc, argv) int argc; char *argv[]; #endif { int c, errflg = 0; int num; char *gamename = NULL; { zword_t zw; int little_endian=0; /* Find out if we are big-endian */ zw=0x0001; if ( *(zbyte_t *)&zw ) { little_endian=1; } #if defined(BIG_END_MODE) || defined(LITTLE_END_MODE) #ifdef BIG_END_MODE if (little_endian) { fprintf (stderr, "%s: On this machine, this program must be compiled with LITTLE_END_MODE defined! Adjust the Makefile and recompile.\n", PROGRAMNAME); exit(EXIT_FAILURE); } #else if (!little_endian) { fprintf (stderr, "%s: On this machine, this program must be compiled with BIG_END_MODE defined! Adjust the Makefile and recompile.\n", PROGRAMNAME); exit(EXIT_FAILURE); } #endif #else fprintf (stderr, "%s: This program must be compiled with either BIG_END_MODE or LITTLE_END_MODE defined! Adjust the Makefile and recompile.\n", PROGRAMNAME); exit(EXIT_FAILURE); #endif } #ifdef STRICTZ /* Initialize the STRICTZ variables. */ strictz_report_mode = STRICTZ_DEFAULT_REPORT_MODE; for (num=0; num= argc) { fprintf(stderr, "%s: option %s requires a value to follow it\n", PROGRAMNAME, argv[c]); errflg = 1; } else { c++; unixoptionlist[num].val = argv[c]; } } } else { fprintf(stderr, "%s: unknown option: %s\n", PROGRAMNAME, argv[c]); errflg = 1; } } else { if (!gamename) gamename = argv[c]; else { fprintf(stderr, "%s: unknown option after story-file: %s\n", PROGRAMNAME, argv[c]); errflg = 1; } } } /* Display usage */ if (errflg || !gamename) { fprintf (stderr, "usage: %s [options...] story-file\n\n", argv[0]); fprintf (stderr, "XZip - a Z-machine interpreter.\nVersion %s by Andrew Plotkin (erkyrath@eblong.com).\n", XZIPVERSION); fprintf (stderr, "Based on ZIP Version 2.0 by Mark Howell.\n"); fprintf (stderr, "Plays Z-machine files of versions 1-5 and version 8.\n\n"); fprintf (stderr, "\t-help: display full list of options\n"); if (errflg==2) { fprintf(stderr, "\n"); for (c=0; c Fade sound in * 0x3507 -> Fade sound out * other -> Replay sound at maximum volume * * Control information: * * This word is divided into two bytes, * the upper byte determines the number of * cycles to play the sound (e.g. how many * times a clock chimes or a dog barks). * The meaning of the lower byte is yet to * be discovered :) * */ #ifdef __STDC__ void sound (int argc, zword_t *argv) #else void sound (argc, argv) int argc; zword_t *argv; #endif { /* Supply default parameters */ if (argc < 4) argv[3] = 0; if (argc < 3) argv[2] = 0xff; if (argc < 2) argv[1] = 2; /* Generic bell sounder */ if (argc == 1 || argv[1] == 2) { xio_bell(); /* --zarf */ /* display_char ('\007'); */ } }/* sound */ #endif /* !defined(AMIGA) */ /* * get_file_name * * Return the name of a file. Flag can be one of: * GAME_SAVE - Save file (write only) * GAME_RESTORE - Save file (read only) * GAME_SCRIPT - Script file (write only) * GAME_RECORD - Keystroke record file (write only) * GAME_PLABACK - Keystroke record file (read only) * */ #ifdef __STDC__ int get_file_name (char *file_name, char *default_name, int flag) #else int get_file_name (file_name, default_name, flag) char *file_name; char *default_name; int flag; #endif { char buffer[127 + 2]; /* 127 is the biggest positive char */ int status = 0; /* If no default file name then supply the standard name */ if (default_name[0] == '\0') { if (flag == GAME_SCRIPT) strcpy (default_name, SCRIPT_NAME); else if (flag == GAME_RECORD || flag == GAME_PLAYBACK) strcpy (default_name, RECORD_NAME); else /* (flag == GAME_SAVE || flag == GAME_RESTORE) */ strcpy (default_name, SAVE_NAME); } /* Prompt for the file name */ output_line ("Enter a file name."); output_string ("(Default is \""); output_string (default_name); output_string ("\"): "); buffer[0] = 127; buffer[1] = 0; (void) get_line (buffer, 0, 0); /* Copy file name from the input buffer */ if (h_type > V4) { unsigned char len = buffer[1]; memcpy (file_name, &buffer[2], len); file_name[len] = '\0'; } else strcpy (file_name, &buffer[1]); /* If nothing typed then use the default name */ if (file_name[0] == '\0') strcpy (file_name, default_name); #if !defined(VMS) /* VMS has file version numbers, so cannot overwrite */ /* Check if we are going to overwrite the file */ if (flag == GAME_SAVE || flag == GAME_SCRIPT || flag == GAME_RECORD) { FILE *tfp; char c; /* Try to access the file */ tfp = fopen (file_name, "r"); if (tfp != NULL) { fclose (tfp); /* If it succeeded then prompt to overwrite */ output_line ("You are about to write over an existing file."); output_string ("Proceed? (Y/N) "); do { c = (char) input_character (0); c = (char) toupper (c); } while (c != 'Y' && c != 'N'); output_char (c); output_new_line (); /* If no overwrite then fail the routine */ if (c == 'N') status = 1; } } #endif /* !defined(VMS) */ /* Record the file name if it was OK */ if (status == 0) record_line (file_name, strlen(file_name)); return (status); }/* get_file_name */ #if !defined(AMIGA) /* * fatal * * Display message and stop interpreter. * */ #ifdef __STDC__ void fatal (const char *s) #else void fatal (s) const char *s; #endif { reset_screen (); printf ("\nFatal error: %s (PC = %lx)\n", s, pc); exit (1); }/* fatal */ #endif /* !defined(AMIGA) */ #if !defined(AMIGA) /* * report_strictz_error * * This handles Z-code error conditions which ought to be fatal errors, * but which players might want to ignore for the sake of finishing the * game. * * The error is provided as both a numeric code and a string. This allows * us to print a warning the first time a particular error occurs, and * ignore it thereafter. * * errnum : Numeric code for error (0 to STRICTZ_NUM_ERRORS-1) * errstr : Text description of error * */ #ifdef STRICTZ #ifdef __STDC__ void report_strictz_error (int errnum, const char *errstr) #else /* __STDC__ */ void report_strictz_error (errnum, errstr) int errnum; const char *errstr; #endif /* __STDC__ */ { int wasfirst; if (errnum <= 0 || errnum >= STRICTZ_NUM_ERRORS) return; if (strictz_report_mode == STRICTZ_REPORT_FATAL) { fatal(errstr); return; } wasfirst = (strictz_error_count[errnum] == 0); strictz_error_count[errnum]++; if ((strictz_report_mode == STRICTZ_REPORT_ALWAYS) || (strictz_report_mode == STRICTZ_REPORT_ONCE && wasfirst)) { char buf[256]; sprintf(buf, "Warning: %s (PC = %lx)", errstr, pc); write_string(buf); if (strictz_report_mode == STRICTZ_REPORT_ONCE) { write_string(" (will ignore further occurrences)"); } else { sprintf(buf, " (occurrence %d)", strictz_error_count[errnum]); write_string(buf); } new_line(); } } /* report_strictz_error */ #endif /* STRICTZ */ #endif /* !defined(AMIGA) */ #if !defined(AMIGA) /* * fit_line * * This routine determines whether a line of text will still fit * on the screen. * * line : Line of text to test. * pos : Length of text line (in characters). * max : Maximum number of characters to fit on the screen. * */ #ifdef __STDC__ int fit_line (const char *line_buffer, int pos, int max) #else int fit_line (line_buffer, pos, max) const char *line_buffer; int pos; int max; #endif { return (pos < max); }/* fit_line */ #endif /* !defined(AMIGA) */ #if !defined(AMIGA) /* * print_status * * Print the status line (type 3 games only). * * argv[0] : Location name * argv[1] : Moves/Time * argv[2] : Score * * Depending on how many arguments are passed to this routine * it is to print the status line. The rendering attributes * and the status line window will be have been activated * when this routine is called. It is to return FALSE if it * cannot render the status line in which case the interpreter * will use display_char() to render it on its own. * * This routine has been provided in order to support * proportional-spaced fonts. * */ #ifdef __STDC__ int print_status (int argc, char *argv[]) #else int print_status (argc, argv) int argc; char *argv[]; #endif { return (FALSE); }/* print_status */ #endif /* !defined(AMIGA) */ #if !defined(AMIGA) /* * set_font * * Set a new character font. Font can be either be: * * TEXT_FONT (1) = normal text character font * GRAPHICS_FONT (3) = graphical character font * * Returns TRUE if succeeded, FALSE if failed. */ #ifdef __STDC__ int set_font (int font_type) #else int set_font (font_type) int font_type; #endif { if (font_type == 1) return TRUE; else return FALSE; }/* set_font */ #endif /* !defined(AMIGA) */ #if !defined(MSDOS) && !defined(AMIGA) /* * set_colours * * Sets screen foreground and background colours. * */ #ifdef __STDC__ void set_colours (int foreground, int background) #else void set_colours (foreground, background) int foreground; int background; #endif { }/* set_colours */ #endif /* !defined(MSDOS) && !defined(AMIGA) */ #if !defined(VMS) && !defined(MSDOS) /* * codes_to_text * * Translate Z-code characters to machine specific characters. These characters * include line drawing characters and international characters. * * The routine takes one of the Z-code characters from the following table and * writes the machine specific text replacement. The target replacement buffer * is defined by MAX_TEXT_SIZE in ztypes.h. The replacement text should be in a * normal C, zero terminated, string. * * Return 0 if a translation was available, otherwise 1. * * Arrow characters (0x18 - 0x1b): * * 0x18 Up arrow * 0x19 Down arrow * 0x1a Right arrow * 0x1b Left arrow * * International characters (0x9b - 0xa3): * * 0x9b a umlaut (ae) * 0x9c o umlaut (oe) * 0x9d u umlaut (ue) * 0x9e A umlaut (Ae) * 0x9f O umlaut (Oe) * 0xa0 U umlaut (Ue) * 0xa1 sz (ss) * 0xa2 open quote (>>) * 0xa3 close quota (<<) * * Line drawing characters (0xb3 - 0xda): * * 0xb3 vertical line (|) * 0xba double vertical line (#) * 0xc4 horizontal line (-) * 0xcd double horizontal line (=) * all other are corner pieces (+) * */ #ifdef __STDC__ int codes_to_text (int c, char *s) #else int codes_to_text (c, s) int c; char *s; #endif { if (c >= 220 && c <= 221) { if (c == 220) { s[0] = 'o'; s[1] = 'e'; } else { s[0] = 'O'; s[1] = 'E'; } s[2] = '\0'; return 0; } if (c >= 155 && c <= 223) { static char xlat[] = "\344\366\374\304\326\334\337\273\253\353\357\377\313\317\341\351\355\363\372\375\301\311\315\323\332\335\340\350\354\362\371\300\310\314\322\331\342\352\356\364\373\302\312\316\324\333\345\305\370\330\343\361\365\303\321\325\346\306\347\307\376\360\336\320\243oO\241\277"; s[0] = xlat[c - 155]; s[1] = '\0'; return 0; } return 1; }/* codes_to_text */ #endif /* !defined(VMS) && !defined(MSDOS) */ xzip/xinit.c0100600000076400007640000001563407173500231012045 0ustar zarfzarf#include #include #include #include #include "ztypes.h" #include "xio.h" #include "arguments.h" #define DEFAULTGEOMETRY "500x600+100+100" #define DEFAULTSTATGEOMETRY "80x24+100+50" static char *defaultfonts[NUMFONTS] = { FND0, FND0, FND1, FND1, FND2, FND2, FND3, FND3, FND4, FND4, FND5, FND5, FND6, FND6, FND7, FND7 }; static char *attrnames[NUMFONTS] = { "n", "r", "b", "rb", "i", "ri", "bi", "rbi", "f", "rf", "bf", "rbf", "if", "rif", "bif", "rbif" }; #ifdef __STDC__ static char *findoption(int key); static int str_to_attr(char *cx); static int str_to_bool(char *cx); #else static char *findoption(); static int str_to_attr(); static int str_to_bool(); #endif #ifdef __STDC__ void xinit_defaultprefs() #else void xinit_defaultprefs() #endif { int ix; strictz_report_mode = STRICTZ_DEFAULT_REPORT_MODE; strictz_declare_spec = FALSE; prefs.leading = 3; prefs.marginx = 4; prefs.marginy = 4; prefs.inputattr = BOLD; prefs.historylength = 20; prefs.paging = FALSE; prefs.fulljustify = TRUE; prefs.buffersize = 4000; prefs.bufferslack = 1000; for (ix=0; ix= STRICTZ_REPORT_NEVER && ix <= STRICTZ_REPORT_FATAL) strictz_report_mode = ix; } cx = findoption(OPT_SPEC); if (cx) strictz_declare_spec = str_to_bool(cx); cx = findoption(OPT_INPUTSTYLE); if (cx) prefs.inputattr = str_to_attr(cx); cx = findoption(OPT_MARGINX); if (cx) prefs.marginx = atoi(cx); cx = findoption(OPT_LEADING); if (cx) prefs.leading = atoi(cx); cx = findoption(OPT_JUSTIFY); if (cx) prefs.fulljustify = str_to_bool(cx); cx = findoption(OPT_AUTORESIZE); if (cx) prefs.autoresize = str_to_bool(cx); cx = findoption(OPT_RESIZEUPWARD); if (cx) prefs.resizeupward = str_to_bool(cx); cx = findoption(OPT_AUTOCLEAR); if (cx) prefs.autoclear = str_to_bool(cx); cx = findoption(OPT_HISTORY); if (cx) prefs.historylength = atoi(cx); cx = findoption(OPT_BUFFER); if (cx) prefs.buffersize = atol(cx); cx = findoption(OPT_BACKGROUND); if (cx && XAllocNamedColor(xiodpy, colormap, cx, &col, &realcol)) { prefs.backcolor = col.pixel; } cx = findoption(OPT_FOREGROUND); if (cx && XAllocNamedColor(xiodpy, colormap, cx, &col, &realcol)) { prefs.forecolor = col.pixel; for (ix=0; ix 1) { for (ix=0; ix, defaulting to <%s>...\n", PROGRAMNAME, prefs.font[ix], defaultfonts[ix]); } fontstr[ix] = XLoadQueryFont(xiodpy, defaultfonts[ix]); if (!fontstr[ix]) { fprintf(stderr, "%s: fatal error: unable to load font <%s>\n", PROGRAMNAME, defaultfonts[ix]); exit(1); } } } else fontstr[ix] = fontstr[ix & (~REVERSE)]; } /* figure out font foo */ for (ix=0; ixascent + fontstr[ix]->descent > lineheight) lineheight = fontstr[ix]->ascent + fontstr[ix]->descent; if (fontstr[ix]->ascent > lineheightoff) lineheightoff = fontstr[ix]->ascent; } lineheight += prefs.leading; /* ensure all cut buffers exist */ for (ix=0; ix<8; ix++) { int size; char *cx = XFetchBuffer(xiodpy, &size, ix); if (!cx) { XStoreBuffer(xiodpy, "#", sizeof(char), ix); } else { free(cx); } } } #ifdef __STDC__ static char *findoption(int key) #else static char *findoption(key) int key; #endif { char *cx; unixoption *opt; opt = (&unixoptionlist[key]); if (!opt->name) { fprintf(stderr, "%s: internal option error on key %d\n", PROGRAMNAME, key); exit(1); } if (opt->val) cx = opt->val; else cx = XGetDefault(xiodpy, PROGRAMNAME, opt->name); return cx; } #ifdef __STDC__ static int str_to_attr(char *cx) #else static int str_to_attr(cx) char *cx; #endif { int ix; for (ix=0; ix #include #include #include #include #include "ztypes.h" #include "xio.h" #define NUMCOMMANDS (768) /* 3*256 */ cmdentry *keycmds[NUMCOMMANDS]; char *keycmdargs[NUMCOMMANDS]; static cmdentry mastertable[] = { {xted_insert, -1, 0, "insert-self"}, {xted_enter, op_Enter, 0, "enter"}, {xted_movecursor, op_ForeChar, 0, "forward-char"}, {xted_movecursor, op_BackChar, 0, "backward-char"}, {xted_movecursor, op_ForeWord, 0, "forward-word"}, {xted_movecursor, op_BackWord, 0, "backward-word"}, {xted_movecursor, op_ForeLine, 0, "forward-line"}, {xted_movecursor, op_BackLine, 0, "backward-line"}, {xted_movecursor, op_BeginLine, 0, "beginning-of-line"}, {xted_movecursor, op_EndLine, 0, "end-of-line"}, {xted_scroll, op_DownPage, 0, "scroll-down"}, {xted_scroll, op_UpPage, 0, "scroll-up"}, {xted_scroll, op_DownLine, 0, "scroll-down-line"}, {xted_scroll, op_UpLine, 0, "scroll-up-line"}, {xted_scroll, op_ToBottom, 0, "scroll-to-bottom"}, {xted_scroll, op_ToTop, 0, "scroll-to-top"}, {xted_delete, op_ForeChar, 0, "delete-next-char"}, {xted_delete, op_BackChar, 0, "delete-char"}, {xted_delete, op_ForeWord, 0, "delete-next-word"}, {xted_delete, op_BackWord, 0, "delete-word"}, {xted_cutbuf, op_Yank, 0, "yank"}, {xted_cutbuf, op_Wipe, 0, "kill-region"}, {xted_cutbuf, op_Copy, 0, "copy-region"}, {xted_cutbuf, op_YankReplace, 0, "yank-pop"}, {xted_cutbuf, op_Kill, 0, "kill-line"}, {xted_cutbuf, op_Untype, 0, "kill-input"}, {xted_history, op_BackLine, 0, "backward-history"}, {xted_history, op_ForeLine, 0, "forward-history"}, {xted_macro, -1, 0, "macro"}, {xtexted_meta, op_Cancel, 1, "cancel"}, {xtexted_meta, op_Escape, 1, "escape"}, {xtexted_meta, op_ExplainKey, 0, "explain-key"}, {xtexted_meta, op_DefineMacro, 0, "define-macro"}, {xtexted_redraw, op_Screen, 0, "redraw-screen"}, {xtexted_redraw, op_Status, 0, "redraw-status"}, {xtexted_redraw, op_AllWindows, 0, "redraw-all-windows"}, {xstat_reset_window_size, op_Zoom, 0, "zoom-status"}, {xstat_reset_window_size, op_Shrink, 0, "shrink-status"}, {xstat_reset_window_size, op_Clear, 0, "clear-status"}, {xted_noop, -1, 0, "no-op"}, {NULL, 0, 0, NULL} }; typedef struct binding_t { unsigned int key; /* or keysym */ int which; /* keytype_main, keytype_meta, keytype_sym */ char *name; } binding; static binding defaultbindings[] = { {XK_Left, keytype_sym, "backward-char"}, {XK_KP_Left, keytype_sym, "backward-char"}, {XK_Right, keytype_sym, "forward-char"}, {XK_KP_Right, keytype_sym, "forward-char"}, {XK_Up, keytype_sym, "backward-history"}, {XK_KP_Up, keytype_sym, "backward-history"}, {XK_Down, keytype_sym, "forward-history"}, {XK_KP_Down, keytype_sym, "forward-history"}, {XK_Begin, keytype_sym, "beginning-of-line"}, {XK_KP_Begin, keytype_sym, "beginning-of-line"}, {XK_End, keytype_sym, "end-of-line"}, {XK_KP_End, keytype_sym, "end-of-line"}, {XK_Prior, keytype_sym, "scroll-up"}, {XK_KP_Prior, keytype_sym, "scroll-up"}, {XK_Next, keytype_sym, "scroll-down"}, {XK_KP_Next, keytype_sym, "scroll-down"}, {XK_Delete, keytype_sym, "delete-char"}, {XK_KP_Delete, keytype_sym, "delete-char"}, {XK_Help, keytype_sym, "explain-key"}, {'w', keytype_meta, "copy-region"}, {'y', keytype_meta, "yank-pop"}, {'b', keytype_meta, "backward-word"}, {'f', keytype_meta, "forward-word"}, {'v', keytype_meta, "scroll-up"}, {'d', keytype_meta, "delete-next-word"}, {'`', keytype_meta, "forward-history"}, {'=', keytype_meta, "backward-history"}, {'z', keytype_meta, "zoom-status"}, {'s', keytype_meta, "shrink-status"}, {'c', keytype_meta, "clear-status"}, {'r', keytype_meta, "define-macro"}, {'0', keytype_meta, "macro"}, {'1', keytype_meta, "macro"}, {'2', keytype_meta, "macro"}, {'3', keytype_meta, "macro"}, {'4', keytype_meta, "macro"}, {'5', keytype_meta, "macro"}, {'6', keytype_meta, "macro"}, {'7', keytype_meta, "macro"}, {'8', keytype_meta, "macro"}, {'9', keytype_meta, "macro"}, {'\177', keytype_meta, "delete-word"}, {'\010', keytype_meta, "delete-word"}, {'\007' /* ctrl-G */, keytype_main, "cancel"}, {'\033' /* Escape */, keytype_main, "escape"}, {'\007' /* ctrl-G */, keytype_meta, "cancel"}, {'\037' /* ctrl-_ */, keytype_main, "explain-key"}, #ifdef TESTING {'\021' /* ctrl-Q */, keytype_main, "scroll-up-line"}, {'\032' /* ctrl-Z */, keytype_main, "scroll-down-line"}, #endif {'\001' /* ctrl-A */, keytype_main, "beginning-of-line"}, {'\005' /* ctrl-E */, keytype_main, "end-of-line"}, {'\002' /* ctrl-B */, keytype_main, "backward-char"}, {'\006' /* ctrl-F */, keytype_main, "forward-char"}, {'\014' /* ctrl-L */, keytype_main, "redraw-all-windows"}, {'\031' /* ctrl-Y */, keytype_main, "yank"}, {'\027' /* ctrl-W */, keytype_main, "kill-region"}, {'\013' /* ctrl-K */, keytype_main, "kill-line"}, {'\025' /* ctrl-U */, keytype_main, "kill-input"}, {'\026' /* ctrl-V */, keytype_main, "scroll-down"}, {'\016' /* ctrl-N */, keytype_main, "forward-line"}, {'\020' /* ctrl-P */, keytype_main, "backward-line"}, {'\177' /* del */, keytype_main, "delete-char"}, {'\010' /* del */, keytype_main, "delete-char"}, {'\004' /* ctrl-D */, keytype_main, "delete-next-char"}, {'\n' /* newline */, keytype_main, "enter"}, {'\r' /* return */, keytype_main, "enter"}, {0, 0, NULL} }; #ifdef __STDC__ static void parse_one_binding(char *key, char *proc, char *marg); #else static void parse_one_binding(); #endif /* initialize key tables */ #ifdef __STDC__ void xkey_init() #else void xkey_init() #endif { int ix, keynum; cmdentry *cmd; binding *bx; for (ix=0; ixname; bx++) { ix = (bx->key & 255); cmd = xkey_find_cmd_by_name(bx->name); if (!cmd) { fprintf(stderr, "%s: unknown function <%s> in default bindings\n", PROGRAMNAME, bx->name); } else { keynum = ix | bx->which; if (keycmds[keynum]) { fprintf(stderr, "%s: key <%s> (%d) defined twice in default bindings\n", PROGRAMNAME, xkey_get_key_name(keynum), ix); } keycmds[keynum] = cmd; } } } #ifdef __STDC__ char *xkey_get_key_name(int key) #else char *xkey_get_key_name(key) int key; #endif { static char buf[32]; char *prefix, *name; int which; which = key & keytype_Mask; key = key & (~keytype_Mask); if (which==keytype_sym) { KeySym ksym = (KeySym)((XK_Home & (~255)) | key); /* I bet this is a stupid thing to do */ name = XKeysymToString(ksym); if (!name) name = "Unknown key"; strcpy(buf, name); return buf; } if (which==keytype_meta) prefix = "meta-"; else prefix = ""; if (iscntrl(key)) { sprintf(buf, "%sctrl-%c", prefix, key+'A'-1); } else { sprintf(buf, "%s%c", prefix, key); } return buf; } /* parse stuff of the form key=proc-name;key=proc-name;... Spaces are optional, c-X and m-X are abbreviations, /123 codes are accepted, and I'm getting a headache. */ #ifdef __STDC__ void xkey_parse_bindings(char *str) #else void xkey_parse_bindings(str) char *str; #endif { char *cx, *cx2, *key, *proc, *marg; char buf[64], nbuf[256], margbuf[256]; int escaped; int keylen, proclen; int hasmarg; cx = str; for (; *cx && isspace(*cx); cx++); while (*cx) { key = cx; escaped = FALSE; for (; *cx && *cx != '=' && !isspace(*cx); cx++) { if (*cx == '\\' && *(cx+1) != '\0') { cx++; if (isdigit(*cx)) { cx++; if (isdigit(*cx)) { cx++; } } } } keylen = cx - key; if (keylen >= sizeof(buf)) { keylen = sizeof(buf)-1; } strncpy(buf, key, keylen); buf[keylen] = '\0'; if (*cx == '\0') { fprintf(stderr, "%s: binding for <%s> has no procedure\n", PROGRAMNAME, buf); break; } for (; *cx && isspace(*cx); cx++); if (*cx != '=') { fprintf(stderr, "%s: unexpected '%c' instead of '=' after <%s>\n", PROGRAMNAME, *cx, buf); break; } cx++; /* skip equals */ for (; *cx && isspace(*cx); cx++); proc = cx; for (; *cx && (*cx=='-' || isalnum(*cx)); cx++); proclen = cx - proc; if (proclen >= sizeof(nbuf)) { proclen = sizeof(nbuf)-1; } strncpy(nbuf, proc, proclen); nbuf[proclen] = '\0'; for (; *cx && isspace(*cx); cx++); hasmarg = FALSE; if (*cx == ',') { cx++; /* skip comma */ for (; *cx && isspace(*cx); cx++); if (*cx != '"') { fprintf(stderr, "%s: unexpected '%c' instead of '\"' after ','\n", PROGRAMNAME, *cx); break; } cx++; /* skip open-quote */ marg = cx; for (; *cx && *cx!='\"'; cx++); if (*cx == '\0') { fprintf(stderr, "%s: unexpected end of string after '\"'\n", PROGRAMNAME); break; } proclen = cx - marg; if (proclen >= sizeof(margbuf)) { proclen = sizeof(margbuf)-1; } strncpy(margbuf, marg, proclen); margbuf[proclen] = '\0'; hasmarg = TRUE; cx++; /* skip close-quote */ for (; *cx && isspace(*cx); cx++); } parse_one_binding(buf, nbuf, hasmarg ? margbuf : NULL); if (*cx == '\0') break; if (*cx != ';') { fprintf(stderr, "%s: unexpected '%c' instead of ';' after <%s>\n", PROGRAMNAME, *cx, nbuf); break; } cx++; /* skip semicolon */ for (; *cx && isspace(*cx); cx++); } } #ifdef __STDC__ static void parse_one_binding(char *key, char *proc, char *marg) #else static void parse_one_binding(key, proc, marg) char *key; char *proc; char *marg; #endif { cmdentry *cmd; int ismeta = FALSE; int isctrl = FALSE; int keynum; KeySym ksym; cmd = xkey_find_cmd_by_name(proc); if (!cmd) { fprintf(stderr, "%s: unknown procedure <%s>\n", PROGRAMNAME, proc); return; } while ((*key=='c' || *key=='C' || *key=='m' || *key=='M') && *(key+1)=='-') { if (*key=='c' || *key=='C') isctrl = TRUE; else ismeta = TRUE; key += 2; } if (strlen(key)==1) { keynum = (*key); if (isctrl) { if (islower(keynum)) keynum = toupper(keynum); if (keynum >= 'A'-1) keynum -= ('A'-1); } if (ismeta) keynum |= keytype_meta; } else { ksym = XStringToKeysym(key); if (ksym==NoSymbol) { fprintf(stderr, "%s: unknown key <%s>\n", PROGRAMNAME, key); return; } if ((ksym & (~255)) == (XK_Home & (~255))) { keynum = keytype_sym | (ksym & (255)); } else if ((ksym & (~255)) == (XK_A & (~255))) { keynum = keytype_main | (ksym & (255)); if (ismeta) keynum |= keytype_meta; } else { fprintf(stderr, "%s: unknown key <%s>\n", PROGRAMNAME, key); return; } } keycmds[keynum] = cmd; if (keycmdargs[keynum]) { free(keycmdargs[keynum]); keycmdargs[keynum] = NULL; } if (marg) { keycmdargs[keynum] = (char *)malloc(sizeof(char) * (1+strlen(marg))); strcpy(keycmdargs[keynum], marg); } } #ifdef __STDC__ cmdentry *xkey_find_cmd_by_name(char *str) #else cmdentry *xkey_find_cmd_by_name(str) char *str; #endif { cmdentry *retval; for (retval = mastertable; retval->func; retval++) { if (!strcmp(str, retval->name)) return retval; } return NULL; } xzip/xmess.c0100600000076400007640000000440606551763103012054 0ustar zarfzarf#include #include #include #include #include "ztypes.h" #include "xio.h" #define LEFTMARGIN 4 #define TOPMARGIN 3 #define TIMEOUT (3) /* in seconds. preference? */ static int messwin_x, messwin_y, messwin_w, messwin_h; static char *message; static int messagelen, message_size; static int messagesticky; static struct timeval messagetime; #ifdef __STDC__ void xmess_init() #else void xmess_init() #endif { message_size = 80; message = (char *)malloc(message_size * sizeof(char)); messagelen = 0; strcpy(message, ""); messagesticky = TRUE; } #ifdef __STDC__ void xmess_resize(int xpos, int ypos, int width, int height) #else void xmess_resize(xpos, ypos, width, height) int xpos; int ypos; int width; int height; #endif { messwin_x = xpos; messwin_y = ypos; messwin_w = width; messwin_h = height; xmess_redraw(); } #ifdef __STDC__ void xmess_redraw() #else void xmess_redraw() #endif { XDrawLine(xiodpy, xiowin, gcblack, messwin_x, messwin_y, messwin_x+messwin_w, messwin_y); if (messagelen) XDrawString(xiodpy, xiowin, gcfont[0], messwin_x+LEFTMARGIN, messwin_y+TOPMARGIN+lineheightoff, message, messagelen); } #ifdef __STDC__ void xmess_set_message(char *str, int sticky) #else void xmess_set_message(str, sticky) char *str; int sticky; #endif { struct timezone tz; if (!str) str = ""; messagelen = strlen(str); if (messagelen >= message_size) { while (messagelen >= message_size) message_size *= 2; message = (char *)realloc(message, message_size * sizeof(char)); } strcpy(message, str); XClearArea(xiodpy, xiowin, messwin_x, messwin_y+1, messwin_w, messwin_h-1, FALSE); if (messagelen) XDrawString(xiodpy, xiowin, gcfont[0], messwin_x+LEFTMARGIN, messwin_y+TOPMARGIN+lineheightoff, message, messagelen); messagesticky = sticky; gettimeofday(&messagetime, &tz); messagetime.tv_sec += TIMEOUT; } #ifdef __STDC__ void xmess_check_timeout() #else void xmess_check_timeout() #endif { struct timezone tz; struct timeval tv; if (messagesticky) return; gettimeofday(&tv, &tz); if (tv.tv_sec > messagetime.tv_sec || (tv.tv_sec == messagetime.tv_sec && tv.tv_usec > messagetime.tv_usec)) { xmess_set_message(NULL, TRUE); } } xzip/xstat.c0100600000076400007640000002164706551763103012066 0ustar zarfzarf#include #include #include #include "ztypes.h" #include "xio.h" #define BLANKATTR (-1) #define SPACEWIDTH (spacewidth[FIXED_FONT]) typedef struct sline_t { int dirtybeg, dirtyend; /* [) protocol; -1,-1 for non-dirty */ int isclear; /* TRUE if text is all blank */ char *text; /* pointer to array of stat_wid chars */ int *attr; /* pointer to array of stat_wid ints */ } sline; /*static int stat_xpos, stat_ypos;*/ /* in pixels */ static int stat_realwid, stat_realhgt; /* in pixels */ static int stat_wid, stat_hgt; /* in chars */ static sline *linelist; /* array of stat_hgt slines */ static int linesused; /* z-machine's idea of the status line size */ static int maxlinesused; /* lines currently visible -- reset only by hitting return. */ static int curlines; /* actual window size */ static int cursorx, cursory; static int cursorattr; static int dotactive; /* is there an insertion mark? */ static int dotdrawn; /* is the insertion mark currently drawn? */ static int dotdrawnx, dotdrawny; static XPoint polydot[3]; #ifdef __STDC__ static void resizewindow(int lines); static void clearlines(int beg, int end); static void flipdot(); #else static void resizewindow(); static void clearlines(); static void flipdot(); #endif #ifdef __STDC__ void xstat_init(int cols, int rows, int xpos, int ypos) #else void xstat_init(cols, rows, xpos, ypos) int cols; int rows; int xpos; int ypos; #endif { int ix; stat_wid = cols; stat_hgt = rows; /*stat_xpos = xpos; stat_ypos = ypos;*/ stat_realwid = cols * SPACEWIDTH; stat_realhgt = rows * lineheight; polydot[0].x = 0; polydot[0].y = 0; polydot[1].x = 4; polydot[1].y = 5; polydot[2].x = -8; polydot[2].y = 0; dotactive = FALSE; dotdrawn = FALSE; dotdrawnx = 0; dotdrawny = 0; linelist = (sline *)malloc(sizeof(sline) * stat_hgt); for (ix=0; ixisclear) { curline->dirtybeg = 0; curline->dirtyend = stat_wid; } } dotdrawn = FALSE; xstat_layout(); } #ifdef __STDC__ void xstat_insert(int ch) #else void xstat_insert(ch) int ch; #endif { sline *curline; if (cursory<0 || cursory>=stat_hgt || cursorx<0 || cursorx>=stat_wid) return; if (cursory+1 > linesused) { xstat_set_window_size(cursory+1); } curline = (&linelist[cursory]); if (curline->text[cursorx] != (char)ch || curline->attr[cursorx] != cursorattr) { curline->text[cursorx] = (char)ch; curline->attr[cursorx] = cursorattr; curline->isclear = FALSE; if (curline->dirtybeg == (-1) || cursorx < curline->dirtybeg) curline->dirtybeg = cursorx; if (curline->dirtyend == (-1) || cursorx+1 > curline->dirtyend) curline->dirtyend = cursorx+1; } cursorx++; if (cursorx == stat_wid) { cursorx = 0; cursory++; } } #ifdef __STDC__ void xstat_newline() #else void xstat_newline() #endif { cursorx = 0; cursory++; } #ifdef __STDC__ void xstat_getpos(int *row, int *col) #else void xstat_getpos(row, col) int *row; int *col; #endif { *col = cursorx+1; *row = cursory+1; } #ifdef __STDC__ void xstat_setpos(int row, int col) #else void xstat_setpos(row, col) int row; int col; #endif { cursorx = col-1; cursory = row-1; } #ifdef __STDC__ void xstat_setattr(int attr) #else void xstat_setattr(attr) int attr; #endif { cursorattr = attr | FIXED_FONT; } #ifdef __STDC__ void xstat_set_window_size(int lines) #else void xstat_set_window_size(lines) int lines; #endif { linesused = lines; if (lines > maxlinesused) maxlinesused = lines; } #ifdef __STDC__ void xstat_set_dot_active(int visible) #else void xstat_set_dot_active(visible) int visible; #endif { if (visible) { /* turn it on */ if (dotactive) return; dotactive = TRUE; } else { /* turn it off */ if (!dotactive) return; dotactive = FALSE; } } /* clear to blankness */ #ifdef __STDC__ void xstat_clear_window() #else void xstat_clear_window() #endif { clearlines(0, stat_hgt); linesused = 0; maxlinesused = linesused; /* because anything below the status window has been cleared */ } #ifdef __STDC__ static void clearlines(int beg, int end) #else static void clearlines(beg, end) int beg; int end; #endif { int ix; int jx; char *cx; int *ax; for (ix=beg; ixdirtybeg == (-1)) continue; beg = curline->dirtybeg; end = curline->dirtyend; pos = beg; while (pos < end) { attr = curline->attr[pos]; for (px=pos; pxattr[px]==attr; px++); if (attr==BLANKATTR) { XClearArea(xiodpy, xioswin, pos*SPACEWIDTH, ix*lineheight, (px-pos)*SPACEWIDTH, lineheight, FALSE); } else if (attr & REVERSE) { XFillRectangle(xiodpy, xioswin, gcsfont[attr], pos*SPACEWIDTH, ix*lineheight, (px-pos)*SPACEWIDTH, lineheight); XDrawString(xiodpy, xioswin, gcsnegfont[attr], pos*SPACEWIDTH, ix*lineheight+lineheightoff, curline->text+pos, (px-pos)); } else { XClearArea(xiodpy, xioswin, pos*SPACEWIDTH, ix*lineheight, (px-pos)*SPACEWIDTH, lineheight, FALSE); XDrawString(xiodpy, xioswin, gcsfont[attr], pos*SPACEWIDTH, ix*lineheight+lineheightoff, curline->text+pos, (px-pos)); } pos = px; } curline->dirtybeg = (-1); curline->dirtyend = (-1); } if (dotactive) { dotdrawnx = cursorx * SPACEWIDTH; dotdrawny = cursory * lineheight + lineheightoff; flipdot(); dotdrawn = TRUE; } if (prefs.autoresize && newsize != curlines) { resizewindow(newsize); } } /* reset the window size to linesused (if max==FALSE) or temporarily to stat_hgt (if max==TRUE) */ #ifdef __STDC__ void xstat_reset_window_size(int op) #else void xstat_reset_window_size(op) int op; #endif { int newsize; if (op==op_Clear) { clearlines(linesused, stat_hgt); xstat_layout(); return; } else if (op==op_Zoom) newsize = stat_hgt; else if (op==op_Shrink) newsize = linesused; else { return; } if (prefs.autoclear && newsize != curlines) { clearlines(newsize, stat_hgt); } if (prefs.autoresize && newsize != curlines) { resizewindow(newsize); } maxlinesused = newsize; } #ifdef __STDC__ static void resizewindow(int lines) #else static void resizewindow(lines) int lines; #endif { XSizeHints szhints; int xp, yp; int newheight; Window child; curlines = lines; newheight = curlines*lineheight; if (newheight==0) newheight++; if (!prefs.resizeupward) { szhints.flags = USSize; szhints.width = stat_wid*SPACEWIDTH; szhints.height = newheight; XResizeWindow(xiodpy, xioswin, szhints.width, szhints.height); XSetNormalHints(xiodpy, xioswin, &szhints); } else { XTranslateCoordinates(xiodpy, xioswin, RootWindow(xiodpy, xioscn), 0, 0, &xp, &yp, &child); yp -= (newheight - stat_realhgt); szhints.flags = PMinSize|PResizeInc|USPosition|USSize; szhints.width = stat_wid*SPACEWIDTH; szhints.height = newheight; szhints.x = xp; szhints.y = yp; szhints.width_inc = spacewidth[FIXED_FONT]; szhints.height_inc = lineheight; szhints.min_width = 1 * szhints.width_inc; szhints.min_height = 1 * szhints.height_inc; XMoveResizeWindow(xiodpy, xioswin, xp, yp, szhints.width, szhints.height); XSetNormalHints(xiodpy, xioswin, &szhints); } } #ifdef __STDC__ static void flipdot() #else static void flipdot() #endif { polydot[0].x = dotdrawnx; polydot[0].y = dotdrawny; XFillPolygon(xiodpy, xioswin, gcsflip, polydot, 3, Convex, CoordModePrevious); } xzip/xtext.c0100600000076400007640000013432006551763103012070 0ustar zarfzarf#include #include #include #include #include "ztypes.h" #include "xio.h" static char *charbuf; static long numchars; static long char_size; typedef struct style_t { int attr; /* flags are REVERSE, BOLD, EMPHASIS, FIXED_FONT */ long pos; /* position this style starts at */ } style; static style *stylelist; static long numstyles; static long styles_size; typedef struct word_t { long pos, len; long width; /* in pixels */ int attr; long *letterpos; /* if not NULL, an array[0..len] of pixel offsets from wordpos; */ } word; #define lineflag_Wrapped (1) /* line is a wrap or split from previous line */ #define lineflag_Extra (2) /* the magic extra line on the end */ typedef struct line_t { long pos; /* line starts here */ long posend; /* number of chars. May not be exactly to start of next line, because it won't include the newline or space that ends the line. */ word *wordlist; long numwords; int flags; } lline; static lline *linelist; static long numlines; static long lines_size; static lline *tmplinelist; static long tmplines_size; static long scrollpos; /* character position at top of screen */ static long scrollline; /* number of line at top of screen, after xtext_layout() */ static long lastlineseen; /* last line read before more stuff was output. (-1) to indicate all lines read. */ static long dotpos, dotlen; /* dotpos is in [0..numchars] */ static long lastdotpos = (-1), lastdotlen = 0; /* cached values -- fiddled inside xtext_layout() */ static long dirtybeg, dirtyend; /* mark the limits of what needs to be laid out, [) format */ static long dirtydelta; /* how much the dirty area has grown (or shrunk) */ static long startlay; /* pos of the char that starts the first laid-out line. */ static int textwin_x, textwin_y, textwin_w, textwin_h; static int scrollwin_x, scrollwin_y, scrollwin_w, scrollwin_h; static int scrollel_top, scrollel_bot; typedef struct histunit { char *str; int len; } histunit; static int historynum, historypos; static histunit *history; /* these are for xtext editing */ static int buflen; static char *buffer; static int *readpos; static long inputfence; static int *killflag; static int originalattr; #define collapse_dot() (dotpos += dotlen, dotlen = 0) #define SIDEMARGIN (4) #define BARENDHEIGHT (12) #define BARWIDTH (17) #define BAREXTRA (4) static XPoint polydot[3]; static long linesperpage; #ifdef __STDC__ static void redrawtext(long beg, long num, int clearnum); static void flip_selection(long dpos, long dlen); static void find_loc_by_pos(long pos, int *xposret, int *yposret); static long find_pos_by_loc(int xpos, int ypos); static long find_line_by_pos(long pos, long guessline); static void measure_word(lline *curline, word *curword); static void adjust_elevator(); void xtext_delete_start(long num); #else static void redrawtext(); static void flip_selection(); static void find_loc_by_pos(); static long find_pos_by_loc(); static long find_line_by_pos(); static void measure_word(); static void adjust_elevator(); void xtext_delete_start(); #endif #ifdef __STDC__ void xtext_init() #else void xtext_init() #endif { char_size = 256; charbuf = (char *)malloc(sizeof(char) * char_size); numchars = 0; styles_size = 8; stylelist = (style *)malloc(sizeof(style) * styles_size); numstyles = 1; stylelist[0].pos = 0; stylelist[0].attr = 0; /* NORMAL style */ lines_size = 8; linelist = (lline *)malloc(sizeof(lline) * lines_size); numlines = 0; tmplines_size = 8; tmplinelist = (lline *)malloc(sizeof(lline) * tmplines_size); historynum = 0; history = (histunit *)malloc(prefs.historylength * sizeof(histunit)); scrollpos = 0; scrollline = 0; startlay = 0; /* not yet used */ dirtybeg = 0; dirtyend = 0; dirtydelta = 0; dotpos = 0; dotlen = 0; polydot[0].x = 0; polydot[0].y = 0; polydot[1].x = SIDEMARGIN; polydot[1].y = 5; polydot[2].x = -2*SIDEMARGIN; polydot[2].y = 0; scrollel_top = (-1); /* indicate elevator is not there */ scrollel_bot = (-1); lastlineseen = 0; } #ifdef __STDC__ void xtext_clear_window() #else void xtext_clear_window() #endif { xtext_delete_start(numlines); } #ifdef __STDC__ void xtext_resize(int xpos, int ypos, int width, int height) #else void xtext_resize(xpos, ypos, width, height) int xpos; int ypos; int width; int height; #endif { scrollwin_x = xpos; scrollwin_w = BARWIDTH; scrollwin_y = ypos+BARENDHEIGHT; scrollwin_h = height-2*BARENDHEIGHT; textwin_x = xpos+scrollwin_w+SIDEMARGIN+prefs.marginx; textwin_y = ypos; textwin_w = width-2*SIDEMARGIN-scrollwin_w-2*prefs.marginx; textwin_h = height; dirtybeg = 0; dirtyend = numchars; dirtydelta = 0; linesperpage = height / lineheight; xtext_layout(); } #ifdef __STDC__ void xtext_redraw() #else void xtext_redraw() #endif { XPoint poly[3]; /* this assumes that an exposure event will not come in between a data update and an xtext_layout call. (unless the exposure event itself forces xtext_layout first?) */ /*flip_selection(dotpos, dotlen);*/ redrawtext(0, -1, -1); flip_selection(dotpos, dotlen); poly[0].x = scrollwin_x + scrollwin_w/2; poly[0].y = textwin_y + 1; poly[1].x = scrollwin_x + 0; poly[1].y = scrollwin_y - 2; poly[2].x = scrollwin_x + scrollwin_w - 1; poly[2].y = scrollwin_y - 2; XFillPolygon(xiodpy, xiowin, gcgrey, poly, 3, Convex, CoordModeOrigin); poly[0].x = scrollwin_x + scrollwin_w/2; poly[0].y = textwin_y + textwin_h - 1; poly[1].x = scrollwin_x + 0; poly[1].y = scrollwin_y + scrollwin_h + 2; poly[2].x = scrollwin_x + scrollwin_w - 1; poly[2].y = scrollwin_y + scrollwin_h + 2; XFillPolygon(xiodpy, xiowin, gcgrey, poly, 3, Convex, CoordModeOrigin); XDrawLine(xiodpy, xiowin, gcblack, scrollwin_x+scrollwin_w, textwin_y, scrollwin_x+scrollwin_w, textwin_h); scrollel_top = (-1); scrollel_bot = (-1); XFillRectangle(xiodpy, xiowin, gcgrey, scrollwin_x, scrollwin_y, scrollwin_w, scrollwin_h); adjust_elevator(); } #ifdef __STDC__ static long back_to_white(long pos) #else static long back_to_white(pos) long pos; #endif { while (pos > 0 && charbuf[pos-1] != ' ' && charbuf[pos-1] != '\n') pos--; return pos; } #ifdef __STDC__ static long fore_to_white(long pos) #else static long fore_to_white(pos) long pos; #endif { while (pos < numchars && charbuf[pos] != ' ' && charbuf[pos] != '\n') pos++; return pos; } #ifdef __STDC__ static long back_to_nonwhite(long pos) #else static long back_to_nonwhite(pos) long pos; #endif { while (pos > 0 && (charbuf[pos-1] == ' ' || charbuf[pos-1] == '\n')) pos--; return pos; } #ifdef __STDC__ static long fore_to_nonwhite(long pos) #else static long fore_to_nonwhite(pos) long pos; #endif { while (pos < numchars && (charbuf[pos] == ' ' || charbuf[pos] == '\n')) pos++; return pos; } /* Coordinates are in screen lines. If num < 0, go to the end. clearnum is the number of lines to clear (may be to a notional line); if 0, don't clear at all; if -1, clear whole window. */ #ifdef __STDC__ static void redrawtext(long beg, long num, int clearnum) #else static void redrawtext(beg, num, clearnum) long beg; long num; int clearnum; #endif { long lx, wx, end, clearend; int ypos, ypos2, xpos; lline *thisline; word *thisword; if (num<0) end = numlines; else { end = beg+num; if (end > numlines) end = numlines; } if (beg < scrollline) beg = scrollline; if (clearnum > 0) { clearend = beg+clearnum; ypos = textwin_y + (beg-scrollline) * lineheight; ypos2 = textwin_y + (clearend-scrollline) * lineheight; if (ypos2 > textwin_y+textwin_h) { ypos2 = textwin_y+textwin_h; } if (ypos != ypos2) XClearArea(xiodpy, xiowin, textwin_x-SIDEMARGIN, ypos, textwin_w+2*SIDEMARGIN, ypos2-ypos, FALSE); } else if (clearnum < 0) { ypos = textwin_y + (beg-scrollline) * lineheight; ypos2 = textwin_y+textwin_h; if (ypos != ypos2) XClearArea(xiodpy, xiowin, textwin_x-SIDEMARGIN, ypos, textwin_w+2*SIDEMARGIN, ypos2-ypos, FALSE); } for (lx=beg; lx= textwin_y + textwin_h) break; xpos = textwin_x; for (wx=0; wxnumwords; wx++) { thisword = thisline->wordlist+wx; if (thisword->attr & REVERSE) XDrawImageString(xiodpy, xiowin, gcfont[thisword->attr], xpos, ypos+lineheightoff, charbuf+thisline->pos+thisword->pos, thisword->len); else XDrawString(xiodpy, xiowin, gcfont[thisword->attr], xpos, ypos+lineheightoff, charbuf+thisline->pos+thisword->pos, thisword->len); xpos += thisword->width; } } } #ifdef __STDC__ static void adjust_elevator() #else static void adjust_elevator() #endif { long newtop, newbot; int barheight = (scrollwin_h-2*BAREXTRA); if (numlines) { newtop = ((barheight*scrollline) / numlines) + BAREXTRA; newbot = ((barheight*(scrollline+linesperpage)) / numlines) + BAREXTRA; if (newtop < BAREXTRA) newtop = BAREXTRA; if (newbot >= scrollwin_h-BAREXTRA) newbot = scrollwin_h-BAREXTRA; } else { newtop = BAREXTRA; newbot = scrollwin_h-BAREXTRA; } if (newtop == scrollel_top && newbot==scrollel_bot) return; if (scrollel_top != (-1) && (scrollel_top >= newbot || newtop >= scrollel_bot)) { /* erase old completely */ XFillRectangle(xiodpy, xiowin, gcgrey, scrollwin_x, scrollwin_y+scrollel_top, scrollwin_w, scrollel_bot-scrollel_top); scrollel_top = (-1); } if (scrollel_top == (-1)) { /* redraw new completely */ XDrawRectangle(xiodpy, xiowin, gcblack, scrollwin_x, scrollwin_y+newtop, scrollwin_w-1, (newbot-newtop)-1); XFillRectangle(xiodpy, xiowin, gcwhite, scrollwin_x+1, scrollwin_y+newtop+1, scrollwin_w-2, (newbot-newtop)-2); scrollel_top = newtop; scrollel_bot = newbot; return; } /* ok, the old and new overlap */ if (newtop < scrollel_top) { XFillRectangle(xiodpy, xiowin, gcwhite, scrollwin_x+1, scrollwin_y+newtop+1, scrollwin_w-2, scrollel_top-newtop); } else if (newtop > scrollel_top) { XFillRectangle(xiodpy, xiowin, gcgrey, scrollwin_x, scrollwin_y+scrollel_top, scrollwin_w, newtop-scrollel_top); } if (newbot > scrollel_bot) { XFillRectangle(xiodpy, xiowin, gcwhite, scrollwin_x+1, scrollwin_y+scrollel_bot-1, scrollwin_w-2, newbot-scrollel_bot); } else if (newbot < scrollel_bot) { XFillRectangle(xiodpy, xiowin, gcgrey, scrollwin_x, scrollwin_y+newbot, scrollwin_w, scrollel_bot-newbot); } XDrawRectangle(xiodpy, xiowin, gcblack, scrollwin_x, scrollwin_y+newtop, scrollwin_w-1, (newbot-newtop)-1); scrollel_top = newtop; scrollel_bot = newbot; } #ifdef __STDC__ static void scroll_to(long newscrollline) #else static void scroll_to(newscrollline) long newscrollline; #endif { long oldscrollline; if (newscrollline > numlines-2) newscrollline = numlines-2; if (newscrollline < 0) newscrollline = 0; scrollpos = linelist[newscrollline].pos; if (scrollline != newscrollline) { oldscrollline = scrollline; if (!xiobackstore || oldscrollline + linesperpage <= newscrollline || newscrollline + linesperpage <= oldscrollline) { scrollline = newscrollline; redrawtext(scrollline, -1, -1); flip_selection(dotpos, dotlen); } else { int ypos1, ypos2, yhgt; flip_selection(dotpos, dotlen); scrollline = newscrollline; if (oldscrollline < newscrollline) { /* scroll down -- things move up */ ypos1 = textwin_y + (newscrollline-oldscrollline) * lineheight; ypos2 = textwin_y + (0) * lineheight; yhgt = (linesperpage-(newscrollline-oldscrollline)) * lineheight; XCopyArea(xiodpy, xiowin, xiowin, gcblack, textwin_x-SIDEMARGIN, ypos1, textwin_w+2*SIDEMARGIN, yhgt, textwin_x-SIDEMARGIN, ypos2); redrawtext(linesperpage + oldscrollline, (newscrollline-oldscrollline), (newscrollline-oldscrollline)); } else { /* scroll up -- things move down */ ypos2 = textwin_y + (oldscrollline-newscrollline) * lineheight; ypos1 = textwin_y + (0) * lineheight; yhgt = (linesperpage-(oldscrollline-newscrollline)) * lineheight; XCopyArea(xiodpy, xiowin, xiowin, gcblack, textwin_x-SIDEMARGIN, ypos1, textwin_w+2*SIDEMARGIN, yhgt, textwin_x-SIDEMARGIN, ypos2); redrawtext(newscrollline, (oldscrollline-newscrollline), (oldscrollline-newscrollline)); } flip_selection(dotpos, dotlen); } adjust_elevator(); } } #ifdef __STDC__ static void refiddle_selection(long oldpos, long oldlen, long newpos, long newlen) #else static void refiddle_selection(oldpos, oldlen, newpos, newlen) long oldpos; long oldlen; long newpos; long newlen; #endif { if (oldlen==0 || newlen==0 || oldpos<0 || newpos<0) { flip_selection(oldpos, oldlen); flip_selection(newpos, newlen); return; } if (oldpos == newpos) { /* start at same place */ if (oldlen < newlen) { flip_selection(oldpos+oldlen, newlen-oldlen); } else if (newlen < oldlen) { flip_selection(oldpos+newlen, oldlen-newlen); } return; } if (oldpos+oldlen == newpos+newlen) { /* end at same place */ if (oldpos < newpos) { flip_selection(oldpos, newpos-oldpos); } else if (newpos < oldpos) { flip_selection(newpos, oldpos-newpos); } return; } flip_selection(oldpos, oldlen); flip_selection(newpos, newlen); } #ifdef __STDC__ static void flip_selection(long dpos, long dlen) #else static void flip_selection(dpos, dlen) long dpos; long dlen; #endif { int xpos, ypos; int xpos2, ypos2; long ybody, ybody2; if (dpos < 0) { return; /* dot hidden */ } if (dlen==0) { find_loc_by_pos(dpos, &xpos, &ypos); if (ypos < 0 || ypos+lineheight >= textwin_h) { return; } polydot[0].x = textwin_x + xpos; polydot[0].y = textwin_y + ypos + lineheightoff; XFillPolygon(xiodpy, xiowin, gcflip, polydot, 3, Convex, CoordModePrevious); } else { find_loc_by_pos(dpos, &xpos, &ypos); find_loc_by_pos(dpos+dlen, &xpos2, &ypos2); if (ypos==ypos2) { /* within one line */ if (xpos!=xpos2 && ypos>=0 && ypos+lineheight=0 && ypos+lineheight=0 && ybody+lineheight= textwin_h) ybody2 = textwin_h; /* main body */ XFillRectangle(xiodpy, xiowin, gcflip, textwin_x, ybody+textwin_y, textwin_w, ybody2-ybody); } if (xpos2 && ypos2>=0 && ypos2+lineheight= lines_size) { while (newnumlines >= lines_size) lines_size *= 2; linelist = (lline *)realloc(linelist, sizeof(lline) * lines_size); } /* clobber old */ for (lx=oldbeg; lxletterpos) { free(thisword->letterpos); } } free(linelist[lx].wordlist); linelist[lx].wordlist = NULL; } if (oldend < numlines && newnumlines != numlines) { memmove(&linelist[oldend+(newnumlines-numlines)], &linelist[oldend], sizeof(lline) * (numlines-oldend)); } /* ### adjust scrollline by difference too? */ numlines = newnumlines; if (newnum) { memcpy(&linelist[oldbeg], &tmplinelist[0], sizeof(lline) * (newnum)); } } /* xpos, ypos are relative to textwin origin */ #ifdef __STDC__ static long find_pos_by_loc(int xpos, int ypos) #else static long find_pos_by_loc(xpos, ypos) int xpos; int ypos; #endif { int ix; long linenum; long wx, atpos, newpos; lline *curline; word *curword; if (ypos < 0) linenum = (-1) - ((-1)-ypos / lineheight); else linenum = ypos / lineheight; linenum += scrollline; if (linenum < 0) return 0; if (linenum >= numlines) return numchars; curline = (&linelist[linenum]); if (xpos < 0) { return curline->pos; /* beginning of line */ } atpos = 0; for (wx=0; wxnumwords; wx++) { newpos = atpos + curline->wordlist[wx].width; if (xpos < newpos) break; atpos = newpos; } if (wx==curline->numwords) { return curline->posend; /* end of line */ } xpos -= atpos; /* now xpos is relative to word beginning */ curword = (&curline->wordlist[wx]); if (!curword->letterpos) measure_word(curline, curword); for (ix=0; ixlen; ix++) { if (xpos <= (curword->letterpos[ix]+curword->letterpos[ix+1])/2) break; } return curline->pos + curword->pos + ix; } /* returns the last line such that pos >= line.pos. guessline is a guess to start searching at; -1 means end of file. Can return -1 if pos is before the start of the layout. */ #ifdef __STDC__ static long find_line_by_pos(long pos, long guessline) #else static long find_line_by_pos(pos, guessline) long pos; long guessline; #endif { long lx; if (guessline < 0 || guessline >= numlines) guessline = numlines-1; if (guessline < numlines-1 && linelist[guessline].pos <= pos) { for (lx=guessline; lx pos) break; } lx--; } else { for (lx=guessline; lx>=0; lx--) { if (linelist[lx].pos <= pos) break; } } return lx; } /* returns values relative to textwin origin, at top of line. */ #ifdef __STDC__ static void find_loc_by_pos(long pos, int *xposret, int *yposret) #else static void find_loc_by_pos(pos, xposret, yposret) long pos; int *xposret; int *yposret; #endif { long lx; long wx, atpos; lline *curline; word *curword; lx = find_line_by_pos(pos, -1); if (lx < 0) { /* somehow before first line laid out */ *xposret = 0; *yposret = (-scrollline) * lineheight; return; } curline = (&linelist[lx]); *yposret = (lx-scrollline) * lineheight; atpos = 0; for (wx=0; wxnumwords; wx++) { if (curline->pos+curline->wordlist[wx].pos+curline->wordlist[wx].len >= pos) break; atpos += curline->wordlist[wx].width; } if (wx==curline->numwords) { *xposret = atpos; return; } curword = (&curline->wordlist[wx]); if (!curword->letterpos) measure_word(curline, curword); atpos += curword->letterpos[pos - (curline->pos+curword->pos)]; *xposret = atpos; } #ifdef __STDC__ static void measure_word(lline *curline, word *curword) #else static void measure_word(curline, curword) lline *curline; word *curword; #endif { int cx; char *buf; int direction; int ascent, descent; XCharStruct overall; long *arr; if (curword->letterpos) free(curword->letterpos); arr = (long *)malloc(sizeof(long) * (curword->len+1)); buf = charbuf+curline->pos+curword->pos; arr[0] = 0; for (cx=0; cxlen-1; cx++) { XTextExtents(fontstr[curword->attr], buf+cx, 1, &direction, &ascent, &descent, &overall); arr[cx+1] = arr[cx] + overall.width; } arr[cx+1] = curword->width; curword->letterpos = arr; } #ifdef __STDC__ static void strip_garbage(char *buf, int len) #else static void strip_garbage(buf, len) char *buf; int len; #endif { int ix; for (ix=0; ix= char_size) { while (newnumchars >= char_size) char_size *= 2; charbuf = (char *)realloc(charbuf, sizeof(char) * char_size); } if (pos < dirtybeg || dirtybeg < 0) dirtybeg = pos; if (newlen != oldlen) { if (pos+oldlen != numchars) { memmove(charbuf+pos+newlen, charbuf+pos+oldlen, sizeof(char) * (numchars-(pos+oldlen))); } if (numchars >= dirtyend) dirtyend = numchars+1; dirtydelta += (newlen-oldlen); } else { if (pos+newlen >= dirtyend) dirtyend = pos+newlen+1; dirtydelta += (newlen-oldlen); } /* copy in the new stuff */ if (newlen) memmove(charbuf+pos, buf, sizeof(char) * newlen); /* diddle the dot */ if (dotpos >= pos+oldlen) { /* starts after changed region */ dotpos += (newlen-oldlen); } else if (dotpos >= pos) { /* starts inside changed region */ if (dotpos+dotlen >= pos+oldlen) { /* ...but ends after it */ dotlen = (dotpos+dotlen)-(pos+oldlen); dotpos = pos+newlen; } else { /* ...and ends inside it */ dotpos = pos+newlen; dotlen = 0; } } else { /* starts before changed region */ if (dotpos+dotlen >= pos+oldlen) { /* ...but ends after it */ dotlen += (newlen-oldlen); } else if (dotpos+dotlen >= pos) { /* ...but ends inside it */ dotlen = (pos+newlen) - dotpos; } } numchars = newnumchars; } #ifdef __STDC__ void xtext_setstyle(long pos, int attr) #else void xtext_setstyle(pos, attr) long pos; int attr; #endif { long sx; if (pos < 0) pos = numchars; for (sx=numstyles-1; sx>=0; sx--) { if (stylelist[sx].pos <= pos) { break; } } if (sx < 0) { printf("### oops, went back behind style 0\n"); return; } if (stylelist[sx].pos == pos) { stylelist[sx].attr = attr; } else { /* insert a style after sx */ sx++; if (numstyles+1 >= styles_size) { styles_size *= 2; stylelist = (style *)realloc(stylelist, sizeof(style) * styles_size); } numstyles++; if (sx < numstyles) { memmove(&stylelist[sx+1], &stylelist[sx], sizeof(style) * (numstyles-sx)); stylelist[sx].pos = pos; stylelist[sx].attr = attr; } } if (pos != numchars) { /* ### should only go to next style */ dirtybeg = pos; dirtyend = numchars; dirtydelta = 0; xtext_layout(); } } #ifdef __STDC__ void xtext_set_lastseen() #else void xtext_set_lastseen() #endif { lastlineseen = numlines; } #ifdef __STDC__ void xtext_end_visible() #else void xtext_end_visible() #endif { long lx; if (lastlineseen < 0 || lastlineseen >= (numlines-linesperpage)-1) { /* straight to end */ if (scrollline < numlines-linesperpage) { scroll_to(numlines-linesperpage); } } else { lx = lastlineseen-1; while (lx < numlines-linesperpage) { scroll_to(lx); xmess_set_message("[Hit any key to continue.]", TRUE); xio_pause(); lx += (linesperpage-1); } scroll_to(numlines-linesperpage); xmess_set_message(NULL, TRUE); } lastlineseen = (-1); } /* delete num lines from the top */ #ifdef __STDC__ void xtext_delete_start(long num) #else void xtext_delete_start(num) long num; #endif { long delchars; long lx, sx, sx2; int origattr; if (num > numlines) num = numlines; if (num < 0) num = 0; if (num == numlines) delchars = numchars; else delchars = linelist[num].pos; if (!delchars) return; /* lines */ slapover(0, 0, num); for (lx=0; lx delchars) break; } if (sx>0) { origattr = stylelist[sx-1].attr; stylelist[0].pos = 0; stylelist[0].attr = origattr; for (sx2=1; sx0 && lx0; styx--) if (stylelist[styx].pos <= startpos) break; if (styx==numstyles-1) nextstylepos = numchars+10; else nextstylepos = stylelist[styx+1].pos; curstyle = stylelist[styx].attr; /* start a-layin' */ tmpl = 0; prevflags = 0; while (startpos= dirtyend && charbuf[startpos]=='\n')) { lline *thisline; long tmpw, tmpwords_size; long widthsofar, spaceswidth; if (tmpl+1 >= tmplines_size) { /* the +1 allows the extra blank line at the end */ tmplines_size *= 2; tmplinelist = (lline *)realloc(tmplinelist, sizeof(lline) * tmplines_size); } thisline = (&tmplinelist[tmpl]); thisline->flags = prevflags; tmpwords_size = 8; thisline->wordlist = (word *)malloc(tmpwords_size * sizeof(word)); tmpw = 0; /*printf("### laying tmpline %d, from charpos %d\n", tmpl, startpos);*/ tmpl++; ix = startpos; widthsofar = 0; prevflags = 0; while (ix= nextstylepos) { /* ahead one style */ styx++; if (styx==numstyles-1) nextstylepos = numchars+10; else nextstylepos = stylelist[styx+1].pos; curstyle = stylelist[styx].attr; } if (tmpw >= tmpwords_size) { tmpwords_size *= 2; thisline->wordlist = (word *)realloc(thisline->wordlist, tmpwords_size * sizeof(word)); } thisword = (&thisline->wordlist[tmpw]); /* --- initialize word structure --- */ thisword->letterpos = NULL; for (jx=ix; jx textwin_w) { prevflags = lineflag_Wrapped; if (tmpw == 0) { /* do something clever -- split the word, put first part in tmplist. */ int letx; long wordwidthsofar = 0; for (letx=ix; letx textwin_w) { break; } wordwidthsofar += overall.width; } jx = letx; overall.width = wordwidthsofar; /* spaceswidth and ejx will be 0 */ /* don't break */ } else { /* ejx and spaceswidth are properly set from last word, trim them off. */ thisword--; thisword->len -= ejx; thisword->width -= spaceswidth; break; } } /* figure out trailing whitespace */ ejx = 0; while (jx+ejxpos = ix-startpos; thisword->len = jx+ejx-ix; thisword->attr = curstyle; thisword->width = overall.width+spaceswidth; widthsofar += thisword->width; tmpw++; ix = jx+ejx; } thisline->pos = startpos; if (tmpw) { word *thisword = (&thisline->wordlist[tmpw-1]); thisline->posend = startpos + thisword->pos + thisword->len; } else { thisline->posend = startpos; } if (ixnumwords = tmpw; if (prefs.fulljustify && prevflags==lineflag_Wrapped && tmpw>1) { /* gonna regret this, I just bet */ long extraspace, each; extraspace = textwin_w - widthsofar; each = extraspace / (tmpw-1); extraspace -= (each*(tmpw-1)); for (jx=0; jxwordlist[jx].width += (each+1); } for (; jxwordlist[jx].width += each; } } startpos = ix; } /* done laying tmp lines */ if (startpos == numchars && (numchars==0 || charbuf[numchars-1]=='\n')) { /* lay one more line! */ lline *thisline; thisline = (&tmplinelist[tmpl]); thisline->flags = lineflag_Extra; tmpl++; thisline->wordlist = (word *)malloc(sizeof(word)); thisline->numwords = 0; thisline->pos = startpos; thisline->posend = startpos; } /*printf("### laid %d tmplines, and startpos now %d (delta %d)\n", tmpl, startpos, dirtydelta);*/ for (lx=overline; lx= startpos-dirtydelta) { /* disturbance is off top of screen -- adjust so that no difference is visible. */ scrollpos += dirtydelta; scrollline += (overline-overlineend) - tmpl; } else { scrollpos += dirtydelta; /* kind of strange, but shouldn't cause trouble */ if (scrollpos >= numchars) scrollpos = numchars-1; if (scrollpos < 0) scrollpos = 0; scrollline = find_line_by_pos(scrollpos, scrollline); needwholeredraw = TRUE; } dirtybeg = -1; dirtyend = -1; dirtydelta = 0; if (needwholeredraw) { redrawtext(scrollline, -1, -1); } else if (tmpl == overlineend-overline) { redrawtext(overline, tmpl, tmpl); } else { if (overlineend > numlines) redrawtext(overline, -1, overlineend-overline); else redrawtext(overline, -1, numlines-overline); } flip_selection(lastdotpos, lastdotlen); adjust_elevator(); } static long drag_firstbeg, drag_firstend; static int drag_inscroll; static int drag_scrollmode; /* 0 for click in elevator; 1 for dragged in elevator; 2 for endzones; 3 for click in background */ static int drag_hitypos; static long drag_origline; /* got a mouse hit. */ #ifdef __STDC__ void xtext_hitdown(int xpos, int ypos, unsigned int button, unsigned int mods, int clicknum) #else void xtext_hitdown(xpos, ypos, button, mods, clicknum) int xpos; int ypos; unsigned int button; unsigned int mods; int clicknum; #endif { long pos; long px, px2; if (xpos < scrollwin_x+scrollwin_w) drag_inscroll = TRUE; else drag_inscroll = FALSE; if (drag_inscroll) { drag_origline = scrollline; drag_hitypos = ypos-textwin_y; switch (button) { /* scrollbar */ case Button1: if (ypos < scrollwin_y) { drag_scrollmode = 2; xted_scroll(op_ToTop); } else if (ypos >= scrollwin_y+scrollwin_h) { drag_scrollmode = 2; xted_scroll(op_ToBottom); } else { if (ypos >= scrollwin_y+scrollel_top && ypos < scrollwin_y+scrollel_bot) drag_scrollmode = 0; else drag_scrollmode = 3; } break; case Button3: if (ypos < scrollwin_y) { drag_scrollmode = 2; xted_scroll(op_UpLine); } else if (ypos >= scrollwin_y+scrollwin_h) { drag_scrollmode = 2; xted_scroll(op_DownLine); } else { if (ypos >= scrollwin_y+scrollel_top && ypos < scrollwin_y+scrollel_bot) drag_scrollmode = 0; else drag_scrollmode = 3; } break; } } else { switch (button) { /* text window */ case Button1: case Button3: xpos -= textwin_x; ypos -= textwin_y; pos = find_pos_by_loc(xpos, ypos); if (button==Button1) { if (!(clicknum & 1)) { px = back_to_white(pos); px2 = fore_to_white(pos); } else { px = pos; px2 = pos; } dotpos = px; dotlen = px2-px; drag_firstbeg = px; drag_firstend = px2; } else { if (pos < dotpos+dotlen/2) { drag_firstbeg = dotpos+dotlen; } else { drag_firstbeg = dotpos; } drag_firstend = drag_firstbeg; if (pos < drag_firstbeg) { if (!(clicknum & 1)) dotpos = back_to_white(pos); else dotpos = pos; dotlen = drag_firstend-dotpos; } else if (pos > drag_firstend) { dotpos = drag_firstbeg; if (!(clicknum & 1)) dotlen = fore_to_white(pos)-drag_firstbeg; else dotlen = pos-drag_firstbeg; } else { dotpos = drag_firstbeg; dotlen = drag_firstend-drag_firstbeg; } } xtext_layout(); break; default: break; } } } #ifdef __STDC__ void xtext_hitmove(int xpos, int ypos, unsigned int button, unsigned int mods, int clicknum) #else void xtext_hitmove(xpos, ypos, button, mods, clicknum) int xpos; int ypos; unsigned int button; unsigned int mods; int clicknum; #endif { long pos, px; if (drag_inscroll) { if (drag_scrollmode==0 || drag_scrollmode==1) { drag_scrollmode = 1; px = ((ypos - drag_hitypos)*numlines) / (scrollwin_h-2*BAREXTRA); scroll_to(drag_origline+px); } } else { xpos -= textwin_x; ypos -= textwin_y; switch (button) { case Button1: case Button3: pos = find_pos_by_loc(xpos, ypos); if (pos < drag_firstbeg) { if (!(clicknum & 1)) dotpos = back_to_white(pos); else dotpos = pos; dotlen = drag_firstend-dotpos; } else if (pos > drag_firstend) { dotpos = drag_firstbeg; if (!(clicknum & 1)) dotlen = fore_to_white(pos)-drag_firstbeg; else dotlen = pos-drag_firstbeg; } else { dotpos = drag_firstbeg; dotlen = drag_firstend-drag_firstbeg; } xtext_layout(); break; default: break; } } } #ifdef __STDC__ void xtext_hitup(int xpos, int ypos, unsigned int button, unsigned int mods, int clicknum) #else void xtext_hitup(xpos, ypos, button, mods, clicknum) int xpos; int ypos; unsigned int button; unsigned int mods; int clicknum; #endif { int px; if (drag_inscroll && (drag_scrollmode==0 || drag_scrollmode==3)) { switch (button) { /* scrollbar */ case Button1: px = (ypos - textwin_y) / lineheight; scroll_to(scrollline+px); break; case Button3: px = (ypos - textwin_y) / lineheight; scroll_to(scrollline-px); break; } } } /* editing functions... */ #ifdef __STDC__ void xted_init(int vbuflen, char *vbuffer, int *vreadpos, int *vkillflag, int firsttime) #else void xted_init(vbuflen, vbuffer, vreadpos, vkillflag, firsttime) int vbuflen; char *vbuffer; int *vreadpos; int *vkillflag; int firsttime; #endif { killflag = vkillflag; *killflag = (-1); buflen = vbuflen; buffer = vbuffer; readpos = vreadpos; if (*readpos) { if (firsttime) { /* Z-machine has already entered the text into the buffer. */ inputfence = numchars - (*readpos); originalattr = stylelist[numstyles-1].attr; xtext_setstyle(inputfence, prefs.inputattr); } else { /* The terp has to enter the text. */ inputfence = numchars; originalattr = stylelist[numstyles-1].attr; xtext_setstyle(-1, prefs.inputattr); xtext_replace(dotpos, 0, buffer, *readpos); xtext_layout(); } } else { inputfence = numchars; originalattr = stylelist[numstyles-1].attr; xtext_setstyle(-1, prefs.inputattr); } historypos = historynum; } #ifdef __STDC__ void xted_insert(int ch) #else void xted_insert(ch) int ch; #endif { if (iscntrl(ch)) ch = ' '; if (dotpos < inputfence) { dotpos = numchars; dotlen = 0; } else { collapse_dot(); } xtext_add(ch, dotpos); xtext_layout(); xtext_end_visible(); } #ifdef __STDC__ void xted_delete(int op) #else void xted_delete(op) int op; #endif { long pos; if (dotpos < inputfence) return; collapse_dot(); switch (op) { case op_BackChar: if (dotpos <= inputfence) return; xtext_replace(dotpos-1, 1, "", 0); break; case op_ForeChar: if (dotpos < inputfence || dotpos >= numchars) return; xtext_replace(dotpos, 1, "", 0); break; case op_BackWord: pos = back_to_nonwhite(dotpos); pos = back_to_white(pos); if (pos < inputfence) pos = inputfence; if (pos >= dotpos) return; xtext_replace(pos, dotpos-pos, "", 0); break; case op_ForeWord: pos = fore_to_nonwhite(dotpos); pos = fore_to_white(pos); if (pos < inputfence) pos = inputfence; if (pos <= dotpos) return; xtext_replace(dotpos, pos-dotpos, "", 0); break; } xtext_layout(); } #ifdef __STDC__ void xted_enter(int op) #else void xted_enter(op) int op; #endif { int len; if (op != op_Enter) return; if (killflag) *killflag = '\n'; xtext_setstyle(-1, originalattr); len = numchars-inputfence; if (len > buflen) len = buflen; memmove(buffer, charbuf+inputfence, len*sizeof(char)); *readpos = len; if (len) { /* add to history */ if (historynum==prefs.historylength) { free(history[0].str); memmove(&history[0], &history[1], (prefs.historylength-1) * (sizeof(histunit))); } else historynum++; history[historynum-1].str = malloc(len*sizeof(char)); memmove(history[historynum-1].str, charbuf+inputfence, len*sizeof(char)); history[historynum-1].len = len; } xtext_add('\n', -1); dotpos = numchars; dotlen = 0; xtext_layout(); /* a somewhat strange place to put the buffer trimmer, but what the heck. The status line shrinker too. */ xstat_reset_window_size(op_Shrink); if (numchars > prefs.buffersize + prefs.bufferslack) { long lx; for (lx=0; lx (numchars-prefs.buffersize)) break; if (lx) { xtext_delete_start(lx); } } } #ifdef __STDC__ void xtext_line_timeout() #else void xtext_line_timeout() #endif { int len; /* same as xted_enter(), but skip the unnecessary stuff. We don't need to add to history, collapse the dot, xtext_layout, trim the buffer, or shrink the status window. */ len = numchars-inputfence; if (len > buflen) len = buflen; memmove(buffer, charbuf+inputfence, len*sizeof(char)); *readpos = len; if (len) { xtext_replace(inputfence, len, "", 0); dotpos = numchars; dotlen = 0; xtext_layout(); } xtext_setstyle(-1, originalattr); } #ifdef __STDC__ void xted_scroll(int op) #else void xted_scroll(op) int op; #endif { switch (op) { case op_UpLine: scroll_to(scrollline-1); break; case op_DownLine: scroll_to(scrollline+1); break; case op_UpPage: scroll_to(scrollline-(linesperpage-1)); break; case op_DownPage: scroll_to(scrollline+(linesperpage-1)); break; case op_ToTop: scroll_to(0); break; case op_ToBottom: scroll_to(numlines); break; } } #ifdef __STDC__ void xted_movecursor(int op) #else void xted_movecursor(op) int op; #endif { long pos; switch (op) { case op_BackChar: collapse_dot(); if (dotpos > 0) dotpos--; break; case op_ForeChar: collapse_dot(); if (dotpos < numchars) dotpos++; break; case op_BackWord: collapse_dot(); dotpos = back_to_nonwhite(dotpos); dotpos = back_to_white(dotpos); break; case op_ForeWord: collapse_dot(); dotpos = fore_to_nonwhite(dotpos); dotpos = fore_to_white(dotpos); break; case op_BeginLine: if (dotlen) { dotlen = 0; } else { if (dotpos >= inputfence) dotpos = inputfence; else { pos = dotpos; while (pos > 0 && charbuf[pos-1] != '\n') pos--; dotpos = pos; } } break; case op_EndLine: if (dotlen) { collapse_dot(); } else { if (dotpos >= inputfence) dotpos = numchars; else { pos = dotpos; while (pos < numchars && charbuf[pos] != '\n') pos++; dotpos = pos; } } break; } xtext_layout(); } #ifdef __STDC__ void xted_cutbuf(int op) #else void xted_cutbuf(op) int op; #endif { char *cx; int num; long tmppos; switch (op) { case op_Copy: if (dotlen) { XRotateBuffers(xiodpy, 1); XStoreBytes(xiodpy, charbuf+dotpos, sizeof(char)*dotlen); } break; case op_Wipe: if (dotlen) { XRotateBuffers(xiodpy, 1); XStoreBytes(xiodpy, charbuf+dotpos, sizeof(char)*dotlen); if (dotpos >= inputfence) { xtext_replace(dotpos, dotlen, "", 0); xtext_layout(); } } break; case op_Yank: collapse_dot(); if (dotpos < inputfence) dotpos = numchars; cx = XFetchBytes(xiodpy, &num); strip_garbage(cx, num); if (cx && num) { tmppos = dotpos; xtext_replace(tmppos, 0, cx, num); dotpos = tmppos; dotlen = num; free(cx); } xtext_layout(); break; case op_Untype: if (numchars == inputfence) break; dotpos = inputfence; dotlen = numchars-inputfence; XRotateBuffers(xiodpy, 1); XStoreBytes(xiodpy, charbuf+dotpos, sizeof(char)*dotlen); xtext_replace(dotpos, dotlen, "", 0); xtext_layout(); break; case op_Kill: if (dotpos < inputfence) { /* maybe extend to end-of-line and copy? */ break; } dotlen = numchars-dotpos; XRotateBuffers(xiodpy, 1); XStoreBytes(xiodpy, charbuf+dotpos, sizeof(char)*dotlen); xtext_replace(dotpos, dotlen, "", 0); xtext_layout(); break; } } #ifdef __STDC__ void xted_history(int op) #else void xted_history(op) int op; #endif { long pos, len; switch (op) { case op_BackLine: if (historypos > 0) { if (dotpos < inputfence) { dotpos = numchars; dotlen = 0; } historypos--; pos = dotpos; xtext_replace(pos, dotlen, history[historypos].str, history[historypos].len); dotpos = pos; dotlen = history[historypos].len; xtext_layout(); } break; case op_ForeLine: if (historypos < historynum) { if (dotpos < inputfence) { dotpos = numchars; dotlen = 0; } historypos++; if (historypos < historynum) { pos = dotpos; xtext_replace(dotpos, dotlen, history[historypos].str, history[historypos].len); dotpos = pos; dotlen = history[historypos].len; } else { pos = dotpos; xtext_replace(dotpos, dotlen, "", 0); dotpos = pos; dotlen = 0; } xtext_layout(); } } } #ifdef __STDC__ void xted_define_macro(int keynum) #else void xted_define_macro(keynum) int keynum; #endif { static cmdentry *macrocommand = NULL; char buf[256]; char *cx, *cx2; if (!macrocommand) { macrocommand = xkey_find_cmd_by_name("macro"); if (!macrocommand) { xmess_set_message("Error: unable to find macro command entry.", FALSE); return; } } if (keycmds[keynum] != macrocommand) { cx = xkey_get_key_name(keynum); sprintf(buf, "Key <%s> is not bound to the macro command.", cx); xmess_set_message(buf, FALSE); return; } if (dotlen == 0) { xmess_set_message("You must highlight a string to define this macro to.", FALSE); return; } cx2 = (char *)malloc(sizeof(char) * (dotlen+1)); memcpy(cx2, charbuf+dotpos, dotlen * sizeof(char)); cx2[dotlen] = '\0'; strip_garbage(cx2, dotlen); if (keycmdargs[keynum]) free(keycmdargs[keynum]); keycmdargs[keynum] = cx2; cx = xkey_get_key_name(keynum); if (!cx2 || !cx2[0]) sprintf(buf, "Macro <%s> is not defined.", cx); else if (strlen(cx2) > (sizeof(buf)-64)) sprintf(buf, "Macro <%s> is defined to something too long to display.", cx); else sprintf(buf, "Macro <%s> defined to \"%s\".", cx, cx2); xmess_set_message(buf, FALSE); } #ifdef __STDC__ void xted_macro(int op) #else void xted_macro(op) int op; #endif { char *str, *cx; str = keycmdargs[op]; if (!str || !str[0]) { char buf[128]; cx = xkey_get_key_name(op); sprintf(buf, "Macro <%s> is not defined.", cx); xmess_set_message(buf, FALSE); return; } if (dotpos < inputfence) { dotpos = numchars; dotlen = 0; } else { collapse_dot(); } xtext_replace(dotpos, 0, str, strlen(str)); xtext_layout(); xtext_end_visible(); } #ifdef __STDC__ void xted_noop(int op) #else void xted_noop(op) int op; #endif { /* good for debugging */ } xzip/xzip.10100600000076400007640000003250507173502143011622 0ustar zarfzarf.TH xzip 1 .SH Name xzip \- X Interface to the Z-code Interpreter .SH Syntax .B xzip [ .I options ... ] .I gamefile .PP The list of options is described below. The .I gamefile should be the filename of a Z-code file or a PICKLE archive containing a Z-code file. .SH Description .I xzip is a clean X Windows interface to games written in Infocom's Z-code game format. It handles Z-code versions 1 through 5, plus the newer version 8. .PP The interface is heavily (well, completely) based on ATK, an X toolkit developed at CMU. Really, I would have preferred to actually do this in ATK... except that then you'd need ATK to run it, and that's 50 .I megabytes of source code. (Honest.) So I just did an imitation. .SH Mouse Commands .PP In the text window: .PP .B Left-click to move the dot to the mouse location. .br .B Click-and-drag to select a large region. .br .B Right-click to extend the selection to the mouse location. .br .B Double-clicking selects a word (or extends the selection one word at a time). .PP In the scroll bar: .PP .B Left-click on the arrows to scroll to the top or bottom. .br .B Right-click on the arrows to scroll up or down one line. .br .B Click-and-drag on the elevator will scroll up and down smoothly. .br .B Left-click in the bar (without dragging) will scroll down by an amount controlled by where in the bar you click. The farther down the bar, the more it scrolls. This is computed so that if you left-click next to a line, that line scrolls to the top of the screen. .br .B Right-click in the bar (without dragging) will scroll up in a similar manner. The top line will scroll down to where you clicked. .SH Key Commands The key commands will be familiar to Emacs users. .I meta\- combinations can be used either by holding down the .I meta key (possibly labelled .I alt or something else) or by pressing .I escape before the desired key. .PP The commands listed below are the defaults. They can be customized with the .I bindings X resource (see below.) \ indicates a function which by default is not bound to any key. .PP .B ctrl-f .I (forward-char) Move dot forward one character. .br .B ctrl-b .I (backward-char) Move dot backward one character. .br .B meta-f .I (forward-word) Move dot forward one word. .br .B meta-b .I (backward-word) Move dot backward one word. .br .B ctrl-a .I (beginning-of-line) Move dot to beginning of line. .br .B ctrl-e .I (end-of-line) Move dot to end of line. .PP .B PageDown, ctrl-v .I (scroll-down) Scroll down one page. .br .B PageUp, meta-v .I (scroll-up) Scroll up one page. .PP .B delete .I (delete-char) Delete character before the dot. .br .B ctrl-d .I (delete-next-char) Delete character after the dot. .br .B meta-delete .I (delete-word) Delete word before the dot. .br .B meta-d .I (delete-next-word) Delete word after the dot. .PP .B ctrl-w .I (kill-region) Cut selection to cut buffer. .br .B meta-w .I (copy-region) Copy selection to cut buffer. .br .B ctrl-y .I (yank) Copy the cut buffer in at the dot. .br .B ctrl-k .I (kill-line) Cut from dot to end of line into the cut buffer. .br .B ctrl-u .I (kill-input) Cut all text typed so far into the cut buffer. .PP .B UpArrow, meta-= .I (backward-history) Move back one line in command history buffer. .br .B DownArrow, meta-` .I (forward-history) Move back one line in command history buffer. .PP .B meta-0...meta-9 .I (macro) Insert a macro string at the dot. By default, all macros are undefined at startup, but you can change this with the .I bindings option. .br .B meta-r .I (define-macro) The next macro key hit will be redefined to be the selection. If there is no selection, or if the next key hit is not a macro key, an error is displayed. .PP .B ctrl-l .I (redraw-all-windows) Redraw text and status windows. .br \ .I (redraw-status) Redraw status window. .br \ .I (redraw-screen) Redraw text window. .br .B meta-z .I (zoom-status) Expand status window to maximum size (only when the .I autoresize option is on.) .br .B meta-s .I (shrink-status) Shrink status window to minimum size (only when the .I autoresize option is on.) .br .B meta-c .I (clear-status) Clear any extra text below the status line in the status window. .PP .B Enter, Return .I (enter) Accept the text that has been typed. .br .B Escape .I (escape) Set escape mode; next key hit will be taken as a .I meta key. .br .B ctrl-g .I (cancel) Cancel escape mode, and anything else that's going on. .br .B Help, ctrl-_ .I (explain-key) Explain the next key hit; this displays the function that the key is bound to, and its argument, if any. .br .B All normal keys .I (insert-self) Insert whatever key is bound to this at the dot. .br \ .I (no-op) Do nothing. Bind a key to this to disable it. .SH Resources and Options All the behavior of .I xzip is controlled by X resources and command-line options. Any particular behavior can be set with either a resource or an option; options override resources. .PP Command-line options go on the command line, looking like, .br .I xzip -option value gamefile .br Note that even binary options like "justify" must be given a value, "yes" or "no". .PP Resources are usually placed in your .I .Xdefaults or .I Xresources file, depending on your system setup. They have the format .br .I xzip.resourcename: value .PP These are the resources and options that you can currently set. The default values are in italics. .PP .IP "\fBgeometry: \fI500x600+100+100\fR" The geometry of the text window, in the usual X geometry format. .IP "\fBstatgeometry: \fI80x24+100+50\fR" The geometry of the status window. Note that the size is given in characters, not in pixels, although the position is still in pixels. This makes it something of a pain to position it in the right or bottom sides of the screen. .IP "\fBforeground: \fIblack\fR" The color of the text and other window decorations. .IP "\fBbackground: \fIwhite\fR" The color of the window background. .IP "\fBgreycolor: \fIgrey60\fR" An intermediate color, used for the scroll bar on color displays. .IP "\fBjustify: \fIyes\fR" If "yes", full-justify the text in the text window. .IP "\fBmarginx: \fI4\fR" Width (in pixels) of the margin between the left edge of the text and the scroll bar. .IP "\fBleading: \fI3\fR" Width (in pixels) of extra space to put between lines of text. .IP "\fBautoresize: \fIyes\fR" If "yes", the status window will automatically resize to be just big enough for the game's status line. (But see "Quirks", below.) .IP "\fBresizeupward: \fIno\fR" If "no", the status window will resize downward; the top edge will stay in place, and the bottom edge will move. If "yes", it will resize upward. At the moment, this doesn't work very well at all. (See "Known Bugs", below.) .IP "\fBautoclear: \fIyes\fR" If "yes", extraneous text in the status window will be cleared after one turn. (See "Quirks", below.) .IP "\fBhistory: \fI20\fR" The number of commands to store in the command history. .IP "\fBbuffer: \fI4000\fR" The amount of text (in characters) to keep in the scrollback buffer. If this is made too large, the program can become very slow. .IP "\fBstrictz: \fI1\fR" The level of reporting of various subtle errors in the game file. 0 means that all errors are silently ignored; 1 (the default) means that each error is reported, but only the first time it occurs; 2 means that each error is reported every time it occurs; 3 means that the interpreter will shut down immediately when an error occurs. .IP "\fBspec: \fIno\fR" If "yes", the interpreter will declare itself to be compliant with the Z-machine Specification version 1.0. This is, basically, a lie, since I have not formally reviewed the source for Spec-1.0 compliance. However, .I xzip does support every Spec-1.0 feature that I know of, except for the color and Unicode options. .IP "\fBinputstyle: \fIb\fR" The style to display your typed input in. This can be .I n for normal text, or .I r, b, rb, i, .I ri, bi, rbi, f, .I rf, bf, rbf, if, .I rif, bif, rbif to specify any combination of Reverse, Bold, Italic, and Fixed. Note that the letters must be in the order shown; you cannot use .I ib to specify italic and bold. .IP "\fBX-color: \fI (same as foreground)\fR" X may be any of .I n, r, b, rb, .I i, ri, bi, rbi, .I f, rf, bf, rbf, .I if, rif, bif, rbif. This allows you to specify the color of any of the sixteen fonts used by .I xzip. For non-reversed fonts, this is the color of the text; for reversed fonts, it is the color of the field on which the text is displayed. (The text of reversed fonts is always in the background color.) .IP "\fBX-font: \fI\fR" X may be any of .I n, b, i, bi, .I f, bf, if, bif. This allows you to specify the sixteen fonts used by .I xzip. (Note that you cannot set the reversed fonts; they always use the same font as their non-reversed counterparts.) .br The status window always uses the fixed-width fonts; the text window usually (but not always) uses proportional fonts. .IP "\fBbindings: \fI(see above)\fR" Key bindings to supplement or override the default bindings. The resource should look like .br .I key=function [, "argument"]; .I key=function [, "argument"] ... .br where .I key is the name of a key, preceded by .I c- to indicate a control key and .I m- to indicate a meta key. .I function should be one of the function names listed in parentheses in the "Key Bindings" section. .I "argument" (which is optional) should be a quoted string which will be passed to the function. Currently, only the .I macro function takes an argument. .br So, for example, .br .I xzip.bindings: c-x=kill-input; m-i=macro,"inventory"; m-d=no-op .br would mean that .I ctrl-x will delete all input, and .I meta-i will enter the string "inventory", and .I meta-d will do nothing. You can have more than one key bound to a function, but you can only have one function bound to a key; later bindings will override earlier ones. .PP Ok, I lied; there's one behavior which is set by an environment variable. If you set INFOCOM_PATH to a directory or colon-separated list of directories, .I xzip will look there for a story file if it doesn't find it in the current directory. .SH Quirks As always, if you highlight colored text, the result may be surprising. Highlighting "normal" text will be fine, and any other fonts which are the same color, but other colors may highlight in strange ways, and could be hard to read. (This is only a problem for text which is highlighted because it's selected. Text in a reverse font looks correct.) .PP Certain games (notably .I Trinity and .I Curses! ) display pop-up windows, by using the status line in a slightly funky way. They expand the status line, display some text, and then immediately shrink the status line again. .br I have done my best to support this in .I xzip \'s two-window system. The pop-up window will be visible from when it is created until the first time you hit .I Return. Then the status window will shrink again. This gives you one "turn" to read the pop-up, which should be sufficient. (In one-window, non-scrolling interpreters, the pop-up appears over your old text, and scrolls away as you continue play.) .br If you turn off the .I autoclear option, pop-ups will not be erased; use .I meta-z to expand the status window and read them after the window shrinks, and .I meta-c to erase them manually. If you do not erase the pop-up, a later pop-up may partially overwrite it, which looks ugly. .br If you turn off the .I autoshrink option, the status window will not shrink, but the pop-up will still be erased (unless you have turned off .I autoclear as well.) .SH Known Bugs The "resizeupward" preference just plain doesn't work. If you use it, the status window will slowly drift downwards as it resizes. .br If a timed input (such as .I Border .I Zone uses) expires while you are editing a line, the dot jumps to the end of the line. .br If a style change occurs in the middle of a word, .I xzip thinks it's okay to break the word there (when wrapping lines.) .br Reverse text has gaps in it in full-justified lines. It also has gaps between lines, in the text window. .br The keybindings are ignored while .I xzip is waiting for a single keystroke (as opposed to a line of input.) .I ctrl-l is hardwired to work, but any other key will just be taken literally. .br Scrolling is slow and awful on X servers without backing store. .br Ignores meta modifier on special keyboard keys (Home, PageUp, etc) .br Parsing of keys in bindings could be cleverer. It ought to understand /123 octal notation at least. .br Ought to have separate font and color prefs for the status window. .br Sometimes makes you place a window by hand, even though the geometry is specified. .SH Author X interface by Andrew Plotkin (erkyrath@eblong.com) .br The Z-code engine is taken from ZIP V2.0.7 by Mark Howell (howell_ma@movies.enet.dec.com) .br For more information, see the web page: .I http://www.eblong.com/zarf/xzip.html .PP You are expressly forbidden to use this program on an Infocom game data file if, in so doing, you violate the copyright notice supplied with the original Infocom game. .br Parts of this program (the files xinit.c, xio.c, xkey.c, xmess.c, xstat.c, xtext.c) are copyrighted by Andrew Plotkin. These files may be distributed, modified, and used freely, with the exception noted above. .br I do not know the exact copyright status of the rest, except that it was written by Mark Howell and thus is probably copyrighted by him. He released it for free, so to the best of my knowledge, it can also be distributed, modified, and used freely, with the exception noted above. xzip/zip.c0100600000076400007640000000660006551763103011515 0ustar zarfzarf/* * zip.c * * Z code interpreter main routine. Plays Infocom type 1, 2, 3, 4 and 5 games. * * Usage: zip [options] story-file-name * * options are: * * -l n - number of lines in display * -c n - number of columns in display * -r n - right margin (default = 0) * -t n - top margin (default = 0) * * This is a no bells and whistles Infocom interpreter for type 1 to 5 games. * It will automatically detect which type of game you want to play. It should * support all type 1 to 5 features and is based loosely on the MS-DOS version * with enhancements to aid portability. Read the readme.1st file for * information on building this program on your favourite operating system. * Please mail me, at the address below, if you find bugs in the code. * * Special thanks to David Doherty and Olaf Barthel for testing this program * and providing invaluable help and code to aid its portability. * * Mark Howell 10-Mar-93 V2.0 howell_ma@movies.enet.dec.com * * Disclaimer: * * You are expressly forbidden to use this program if in so doing you violate * the copyright notice supplied with the original Infocom game. * */ #include "ztypes.h" #ifdef __STDC__ static void configure (zbyte_t, zbyte_t); #else static void configure (); #endif /* * main * * Initialise environment, start interpreter, clean up. * */ #ifdef __STDC__ int main (int argc, char *argv[]) #else int main (argc, argv) int argc; char *argv[]; #endif { process_arguments (argc, argv); configure (V1, V8); initialize_screen (); load_cache (); restart (); (void) interpret (); unload_cache (); close_story (); close_script (); reset_screen (); exit (EXIT_SUCCESS); return (0); }/* main */ /* * configure * * Initialise global and type specific variables. * */ #ifdef __STDC__ static void configure (zbyte_t min_version, zbyte_t max_version) #else static void configure (min_version, max_version) zbyte_t min_version; zbyte_t max_version; #endif { zbyte_t header[PAGE_SIZE]; read_page (0, header); datap = header; h_type = get_byte (H_TYPE); if (h_type < min_version || h_type > max_version || (get_byte (H_CONFIG) & CONFIG_BYTE_SWAPPED)) fatal ("wrong game or version"); if (h_type < V4) { story_scaler = 2; story_shift = 1; property_mask = P3_MAX_PROPERTIES - 1; property_size_mask = 0xe0; } else if (h_type < V8) { story_scaler = 4; story_shift = 2; property_mask = P4_MAX_PROPERTIES - 1; property_size_mask = 0x3f; } else { story_scaler = 8; story_shift = 3; property_mask = P4_MAX_PROPERTIES - 1; property_size_mask = 0x3f; } h_config = get_byte (H_CONFIG); h_version = get_word (H_VERSION); h_data_size = get_word (H_DATA_SIZE); h_start_pc = get_word (H_START_PC); h_words_offset = get_word (H_WORDS_OFFSET); h_objects_offset = get_word (H_OBJECTS_OFFSET); h_globals_offset = get_word (H_GLOBALS_OFFSET); h_restart_size = get_word (H_RESTART_SIZE); h_flags = get_word (H_FLAGS); h_synonyms_offset = get_word (H_SYNONYMS_OFFSET); h_file_size = get_word (H_FILE_SIZE); if (h_file_size == 0) h_file_size = get_story_size (); h_checksum = get_word (H_CHECKSUM); h_alternate_alphabet_offset = get_word (H_ALTERNATE_ALPHABET_OFFSET); datap = NULL; }/* configure */ xzip/text.c0100600000076400007640000006274407171236344011713 0ustar zarfzarf/* * text.c * * Text manipulation routines * */ #include "ztypes.h" static int saved_formatting = ON; /* static int line_pos = 0; */ /* static int char_count = 0; no longer used --zarf */ static int story_buffer = 0; static int story_pos = 0; static int story_count = 0; /* * decode_text * * Convert encoded text to ASCII. Text is encoded by squeezing each character * into 5 bits. 3 x 5 bit encoded characters can fit in one word with a spare * bit left over. The spare bit is used to signal to end of a string. The 5 bit * encoded characters can either be actual character codes or prefix codes that * modifier the following code. * */ #ifdef __STDC__ void decode_text (unsigned long *address) #else void decode_text (address) unsigned long *address; #endif { int i, synonym_flag, synonym = 0, ascii_flag, ascii = 0; int data, code, shift_state, shift_lock; unsigned long addr; /* Set state variables */ shift_state = 0; shift_lock = 0; ascii_flag = 0; synonym_flag = 0; do { /* * Read one 16 bit word. Each word contains three 5 bit codes. If the * high bit is set then this is the last word in the string. */ data = read_data_word (address); for (i = 10; i >= 0; i -= 5) { /* Get code, high bits first */ code = (data >> i) & 0x1f; /* Synonym codes */ if (synonym_flag) { synonym_flag = 0; synonym = (synonym - 1) * 64; addr = (unsigned long) get_word (h_synonyms_offset + synonym + (code * 2)) * 2; decode_text (&addr); shift_state = shift_lock; /* ASCII codes */ } else if (ascii_flag) { /* * If this is the first part ASCII code then remember it. * Because the codes are only 5 bits you need two codes to make * one eight bit ASCII character. The first code contains the * top 3 bits. The second code contains the bottom 5 bits. */ if (ascii_flag++ == 1) ascii = code << 5; /* * If this is the second part ASCII code then assemble the * character from the two codes and output it. */ else { ascii_flag = 0; write_zchar ((char) (ascii | code)); } /* Character codes */ } else if (code > 5) { code -= 6; /* * If this is character 0 in the punctuation set then the next two * codes make an ASCII character. */ if (shift_state == 2 && code == 0) ascii_flag = 1; /* * If this is character 1 in the punctuation set then this * is a new line. */ else if (shift_state == 2 && code == 1 && h_type > V1) new_line (); /* * This is a normal character so select it from the character * table appropriate for the current shift state. */ else write_zchar (lookup_table[shift_state][code]); shift_state = shift_lock; /* Special codes 0 to 5 */ } else { /* * Space: 0 * * Output a space character. * */ if (code == 0) { write_zchar (' '); } else { /* * The use of the synonym and shift codes is the only difference between * the different versions. */ if (h_type < V3) { /* * Newline or synonym: 1 * * Output a newline character or set synonym flag. * */ if (code == 1) { if (h_type == V1) new_line (); else { synonym_flag = 1; synonym = code; } /* * Shift keys: 2, 3, 4 or 5 * * Shift keys 2 & 3 only shift the next character and can be used regardless of * the state of the shift lock. Shift keys 4 & 5 lock the shift until reset. * * The following code implements the the shift code state transitions: * * +-------------+-------------+-------------+-------------+ * | Shift State | Lock State | * +-------------+-------------+-------------+-------------+-------------+ * | Code | 2 | 3 | 4 | 5 | * +-------------+-------------+-------------+-------------+-------------+ * | lowercase | uppercase | punctuation | uppercase | punctuation | * | uppercase | punctuation | lowercase | punctuation | lowercase | * | punctuation | lowercase | uppercase | lowercase | uppercase | * +-------------+-------------+-------------+-------------+-------------+ * */ } else { if (code < 4) shift_state = (shift_lock + code + 2) % 3; else shift_lock = shift_state = (shift_lock + code) % 3; } } else { /* * Synonym table: 1, 2 or 3 * * Selects which of three synonym tables the synonym * code following in the next code is to use. * */ if (code < 4) { synonym_flag = 1; synonym = code; /* * Shift key: 4 or 5 * * Selects the shift state for the next character, * either uppercase (4) or punctuation (5). The shift * state automatically gets reset back to lowercase for * V3+ games after the next character is output. * */ } else { shift_state = code - 3; shift_lock = 0; } } } } } } while ((data & 0x8000) == 0); }/* decode_text */ /* * encode_text * * Pack a string into up to 9 codes or 3 words. * */ #ifdef __STDC__ void encode_text (int len, const char *s, short *buffer) #else void encode_text (len, s, buffer) int len; const char *s; short *buffer; #endif { int i, j, prev_table, table, next_table, shift_state, code, codes_count; char codes[9]; /* Initialise codes count and prev_table number */ codes_count = 0; prev_table = 0; /* Scan do the string one character at a time */ while (len--) { /* * Set the table and code to be the ASCII character inducer, then * look for the character in the three lookup tables. If the * character isn't found then it will be an ASCII character. */ table = 2; code = 0; for (i = 0; i < 3; i++) { for (j = 0; j < 26; j++) { if (lookup_table[i][j] == *s) { table = i; code = j; } } } /* * Type 1 and 2 games differ on how the shift keys are used. Switch * now depending on the game version. */ if (h_type < V3) { /* * If the current table is the same as the previous table then * just store the character code, otherwise switch tables. */ if (table != prev_table) { /* Find the table for the next character */ next_table = 0; if (len) { next_table = 2; for (i = 0; i < 3; i++) { for (j = 0; j < 26; j++) { if (lookup_table[i][j] == s[1]) next_table = i; } } } /* * Calculate the shift key. This magic. See the description in * decode_text for more information on version 1 and 2 shift * key changes. */ shift_state = (table + (prev_table * 2)) % 3; /* Only store the shift key if there is a change in table */ if (shift_state) { /* * If the next character as the uses the same table as * this character then change the shift from a single * shift to a shift lock. Also remember the current * table for the next iteration. */ if (next_table == table) { shift_state += 2; prev_table = table; } else prev_table = 0; /* Store the code in the codes buffer */ if (codes_count < 9) codes[codes_count++] = (char) (shift_state + 1); } } } else { /* * For V3 games each uppercase or punctuation table is preceded * by a separate shift key. If this is such a shift key then * put it in the codes buffer. */ if (table && codes_count < 9) codes[codes_count++] = (char) (table + 3); } /* Put the character code in the code buffer */ if (codes_count < 9) codes[codes_count++] = (char) (code + 6); /* * Cannot find character in table so treat it as a literal ASCII * code. The ASCII code inducer (code 0 in table 2) is followed by * the high 3 bits of the ASCII character followed by the low 5 * bits to make 8 bits in total. */ if (table == 2 && code == 0) { if (codes_count < 9) codes[codes_count++] = (char) ((*s >> 5) & 0x07); if (codes_count < 9) codes[codes_count++] = (char) (*s & 0x1f); } /* Advance to next character */ s++; } /* Pad out codes with shift 5's */ while (codes_count < 9) codes[codes_count++] = 5; /* Pack codes into buffer */ buffer[0] = ((short) codes[0] << 10) | ((short) codes[1] << 5) | (short) codes[2]; buffer[1] = ((short) codes[3] << 10) | ((short) codes[4] << 5) | (short) codes[5]; buffer[2] = ((short) codes[6] << 10) | ((short) codes[7] << 5) | (short) codes[8]; /* Terminate buffer at 6 or 9 codes depending on the version */ if (h_type < V4) buffer[1] |= 0x8000; else buffer[2] |= 0x8000; }/* encode_text */ /* * write_zchar * * High level Z-code character output routine. Translates Z-code characters to * machine specific character(s) before output. If it cannot translate it then * use the default translation. If the character is still unknown then display * a '?'. * */ #ifdef __STDC__ void write_zchar (int c) #else void write_zchar (c) int c; #endif { char xlat_buffer[MAX_TEXT_SIZE + 1]; int i; c = (unsigned int) (c & 0xff); /* If character is not special character then just write it */ if (c >= ' ' && c <= '~') { write_char (c); } else if (c == 13) { /* write_char ('\r'); */ new_line (); } else { /* Put default character in translation buffer */ xlat_buffer[0] = '?'; xlat_buffer[1] = '\0'; /* If translation fails then supply a default */ if (codes_to_text (c, xlat_buffer)) { if (c > 23 && c < 28) { /* Arrow keys - these must the keyboard keys used for input */ static char xlat[4] = { '\\', '/', '+', '-' }; xlat_buffer[0] = xlat[c - 24]; xlat_buffer[1] = '\0'; } else if (c == 0) { /* Null - print nothing */ xlat_buffer[0] = '\0'; } else if (c < 32) { /* Some other control character: print an octal escape. */ xlat_buffer[0] = '\\'; xlat_buffer[1] = '0' + ((c >> 6) & 7); xlat_buffer[2] = '0' + ((c >> 3) & 7); xlat_buffer[3] = '0' + (c & 7); xlat_buffer[4] = '\0'; } else if (c > 178 && c < 219) { /* IBM line drawing characters to ASCII characters */ if (c == 179) xlat_buffer[0] = '|'; else if (c == 186) xlat_buffer[0] = '#'; else if (c == 196) xlat_buffer[0] = '-'; else if (c == 205) xlat_buffer[0] = '='; else xlat_buffer[0] = '+'; xlat_buffer[1] = '\0'; } else if (c > 154 && c < 164) { /* German character replacements */ static char xlat[] = "aeoeueAeOeUess>><<"; xlat_buffer[0] = xlat[((c - 155) * 2) + 0]; xlat_buffer[1] = xlat[((c - 155) * 2) + 1]; xlat_buffer[2] = '\0'; } } /* Substitute translated characters */ for (i = 0; xlat_buffer[i] != '\0'; i++) write_char ((unsigned char) xlat_buffer[i]); } }/* write_zchar */ /* * write_char * * High level character output routine. The write_char routine is slightly * complicated by the fact that the output can be limited by a fixed character * count, as well as, filling up the buffer. * */ #ifdef __STDC__ void write_char (int c) #else void write_char (c) int c; #endif { char *cp; int right_len; /* Only do if text formatting is turned on */ if (redirect_depth) { /* If redirect is on then write the character to the status line for V1 to V3 games or into the writeable data area for V4+ games */ if (h_type < V4) status_line[status_pos++] = (char) c; else { set_byte (story_pos++, c); story_count++; } } else { /* No formatting or output redirection, so just output the character */ if (c == 13) c = '\n'; script_char (c); output_char (c); } }/* write_char */ /* * set_video_attribute * * Set a video attribute. Write the video mode, from 0 to 8, incremented. * This is so the output routines don't confuse video attribute 0 as the * end of the string. * */ #ifdef __STDC__ void set_video_attribute (zword_t mode) #else void set_video_attribute (mode) zword_t mode; #endif { if ((int) mode <= MAX_ATTRIBUTE) write_char ((char) ++mode); }/* set_video_attribute */ /* * write_string * * Output a string * */ #ifdef __STDC__ void write_string (const char *s) #else void write_string (s) const char *s; #endif { while (*s) write_zchar (*s++); }/* write_string */ /* * flush_buffer * * Send output buffer to the screen. * */ #ifdef __STDC__ void flush_buffer (int flag) #else void flush_buffer (flag) int flag; #endif { /* Terminate the line */ /* ain't no bufferin' no more --zarf */ #if 0 line[line_pos] = '\0'; /* Send the line buffer to the printer */ script_string (line); /* Send the line buffer to the screen */ output_string (line); /* Reset the buffer pointer */ line_pos = 0; #endif }/* flush_buffer */ /* * set_format_mode * * Set the format mode flag. Formatting disables writing into the output buffer. * */ #ifdef __STDC__ void set_format_mode (zword_t flag) #else void set_format_mode (flag) zword_t flag; #endif { /* Flush any current output */ flush_buffer (FALSE); /* Set formatting depending on the flag */ if (flag) formatting = ON; else formatting = OFF; }/* set_format_mode */ /* * set_print_modes * * Set various printing modes. These can be: disabling output, scripting and * redirecting output. Redirection is peculiar. I use it to format the status * line for V1 to V3 games, otherwise it wasn't used. V4 games format the status line * themselves in an internal buffer in the writeable data area. To use the normal * text decoding routines they have to redirect output to the writeable data * area. This is done by passing in a buffer pointer. The first word of the * buffer will receive the number of characters written since the output was * redirected. The remainder of the buffer will contain the redirected text. * */ typedef struct redirect_stash_struct { zword_t count; zword_t buffer; zword_t pos; } redirect_stash_t; #ifdef __STDC__ void set_print_modes (zword_t type, zword_t option) #else void set_print_modes (type, option) zword_t type; zword_t option; #endif { static int redirect_size = 0; static redirect_stash_t *stash = NULL; if ((short) type == 1) { /* Turn on text output */ outputting = ON; } else if ((short) type == 2) { /* Turn on scripting */ open_script (); } else if ((short) type == 3) { /* Turn on output redirection */ if (redirect_depth == 0) { /* Disable text formatting during redirection */ saved_formatting = formatting; formatting = OFF; /* Enable text redirection */ redirect_depth = 1; } else { if (redirect_size == 0) { redirect_size = 4; stash = (redirect_stash_t *)malloc( redirect_size * sizeof(redirect_stash_t)); } if (redirect_depth > redirect_size) { redirect_size *= 2; stash = (redirect_stash_t *)realloc(stash, redirect_size * sizeof(redirect_stash_t)); } if (h_type < V4) { stash[redirect_depth-1].pos = status_pos; } else { stash[redirect_depth-1].pos = story_pos; stash[redirect_depth-1].buffer = story_buffer; stash[redirect_depth-1].count = story_count; } redirect_depth++; } /* Set up the redirection pointers */ if (h_type < V4) status_pos = 0; else { story_count = 0; story_buffer = option; story_pos = option + 2; } } else if ((short) type == 4) { /* Turn on input recording */ open_record (); } else if ((short) type == -1) { /* Turn off text output */ outputting = OFF; } else if ((short) type == -2) { /* Turn off scripting */ close_script (); } else if ((short) type == -3) { /* Turn off output redirection */ if (redirect_depth) { if (redirect_depth == 1) { /* Restore the format mode and turn off redirection */ formatting = saved_formatting; redirect_depth = 0; /* Terminate the redirection buffer and store the count of character in the buffer into the first word of the buffer */ if (h_type > V3) set_word (story_buffer, story_count); } else { if (h_type > V3) set_word (story_buffer, story_count); redirect_depth--; if (h_type < V4) { status_pos = stash[redirect_depth-1].pos; } else { story_pos = stash[redirect_depth-1].pos; story_buffer = stash[redirect_depth-1].buffer; story_count = stash[redirect_depth-1].count; } } } } else if ((short) type == -4) { /* Turn off input recording */ close_record (); } }/* set_print_modes */ /* * print_character * * Write a character. * */ #ifdef __STDC__ void print_character (zword_t c) #else void print_character (c) zword_t c; #endif { write_zchar ((char) c); }/* print_character */ /* * print_number * * Write a signed number. * */ #ifdef __STDC__ void print_number (zword_t num) #else void print_number (num) zword_t num; #endif { int i, count; char buffer[10]; i = (short) num; sprintf (buffer, "%d", i); count = strlen (buffer); for (i = 0; i < count; i++) write_char (buffer[i]); }/* print_number */ /* * print_address * * Print using a packed address. Packed addresses are used to save space and * reference addresses outside of the data region. * */ #ifdef __STDC__ void print_address (zword_t packed_address) #else void print_address (packed_address) zword_t packed_address; #endif { unsigned long address; /* Convert packed address to real address */ address = (unsigned long) packed_address * story_scaler; /* Decode and output text at address */ decode_text (&address); }/* print_address */ /* * print_offset * * Print using a real address. Real addresses are just offsets into the * data region. * */ #ifdef __STDC__ void print_offset (zword_t offset) #else void print_offset (offset) zword_t offset; #endif { unsigned long address; address = offset; /* Decode and output text at address */ decode_text (&address); }/* print_offset */ /* * print_object * * Print an object description. Object descriptions are stored as ASCIC * strings at the front of the property list for the object. * */ #ifdef __STDC__ void print_object (zword_t obj) #else void print_object (obj) zword_t obj; #endif { zword_t offset; unsigned long address; /* Check for NULL object */ if (obj == 0) return; /* Calculate address of property list */ offset = get_object_address (obj); offset += (h_type < V4) ? O3_PROPERTY_OFFSET : O4_PROPERTY_OFFSET; /* Read the property list address and skip the count byte */ address = (unsigned long) get_word (offset) + 1; /* Decode and output text at address */ decode_text (&address); }/* print_object */ /* * print_literal * * Print the string embedded in the instruction stream at this point. All * strings that do not need to be referenced by address are embedded in the * instruction stream. All strings that can be refered to by address are placed * at the end of the code region and referenced by packed address. * */ #ifdef __STDC__ void print_literal (void) #else void print_literal () #endif { /* Decode and output text at PC */ decode_text (&pc); }/* print_literal */ /* * println_return * * Print a string embedded in the instruction stream as with print_literal, * except flush the output buffer and write a new line. After this return from * the current subroutine with a status of true. * */ #ifdef __STDC__ void println_return (void) #else void println_return () #endif { print_literal (); new_line (); ret (TRUE); }/* println_return */ /* * new_line * * Simply flush the current contents of the output buffer followed by a new * line. * */ #ifdef __STDC__ void new_line (void) #else void new_line () #endif { /* Only flush buffer if story redirect is off */ if (redirect_depth == 0) { flush_buffer (TRUE); script_new_line (); output_new_line (); } else write_char ('\r'); }/* new_line */ /* * print_time * * Print the time as HH:MM [am|pm]. This is a bit language dependent and can * quite easily be changed. If you change the size of the time string output * then adjust the status line position in display_status_line. * */ #ifdef __STDC__ void print_time (int hours, int minutes) #else void print_time (hours, minutes) int hours; int minutes; #endif { int pm_indicator; /* Remember if time is pm */ pm_indicator = (hours < 12) ? OFF : ON; /* Convert 24 hour clock to 12 hour clock */ hours %= 12; if (hours == 0) hours = 12; /* Write hour right justified */ if (hours < 10) write_char (' '); print_number (hours); /* Write hours/minutes separator */ write_char (':'); /* Write minutes zero filled */ if (minutes < 10) write_char ('0'); print_number (minutes); /* Write the am or pm string */ if (pm_indicator == ON) write_string (" pm"); else write_string (" am"); }/* print_time */ /* * encode * * Convert text to packed text. * */ #ifdef __STDC__ void encode (zword_t word_addr, zword_t word_length, zword_t word_offset, zword_t dest_addr) #else void encode (word_addr, word_length, word_offset, dest_addr) zword_t word_addr; zword_t word_length; zword_t word_offset; zword_t dest_addr; #endif { short word[3]; int i; /* Encode the word */ encode_text (word_length, (const char *) &datap[word_addr + word_offset], word); /* Move the encoded word, byte swapped, into the destination buffer */ for (i = 0; i < 3; i++, dest_addr += 2) set_word (dest_addr, word[i]); }/* encode */ xzip/unixio.c0100600000076400007640000002712006551763103012226 0ustar zarfzarf/* unixio.c */ #include "ztypes.h" #if !defined(BSD) || !defined(SYSTEM_FIVE) || !defined(POSIX) #define BSD #endif /* !defined(BSD) || !defined(SYSTEM_FIVE) || !defined(POSIX) */ #if defined(BSD) #include #endif /* defined(BSD) */ #if defined(SYSTEM_FIVE) #include #endif /* defined(SYSTEM_FIVE) #if defined(POSIX) #include #endif /* defined(POSIX) */ #include #include #include static int screen_inited = 0; static int current_row = 1; static int current_col = 1; static int saved_row; static int saved_col; static int cursor_saved = OFF; static char tcbuf[1024]; static char cmbuf[1024]; static char *cmbufp; static char *CE, *CL, *CM, *CS, *DL, *MD, *ME, *MR, *SE, *SO, *TE, *TI, *UE, *US; #define GET_TC_STR(p1, p2) if ((p1 = tgetstr (p2, &cmbufp)) == NULL) p1 = "" #define BELL 7 static void outc (); static void display_string (); static int wait_for_char (); static int read_key (); static void set_cbreak_mode (); static void rundown (); extern int tgetent (); extern int tgetnum (); extern char *tgetstr (); extern char *tgoto (); extern void tputs (); static void outc (c) int c; { putchar (c); }/* outc */ void initialize_screen () { char *term; struct winsize winsz; int row, col; if ((term = getenv ("TERM")) == NULL) fatal ("No TERM environment variable"); if (tgetent (tcbuf, term) <= 0) fatal ("No termcap entry for this terminal"); cmbufp = cmbuf; GET_TC_STR (CE, "ce"); GET_TC_STR (CL, "cl"); GET_TC_STR (CM, "cm"); GET_TC_STR (CS, "cs"); GET_TC_STR (DL, "dl"); GET_TC_STR (MD, "md"); GET_TC_STR (ME, "me"); GET_TC_STR (MR, "mr"); GET_TC_STR (SE, "se"); GET_TC_STR (SO, "so"); GET_TC_STR (TE, "te"); GET_TC_STR (TI, "ti"); GET_TC_STR (UE, "ue"); GET_TC_STR (US, "us"); if (ioctl(fileno(stdin), TIOCGWINSZ, &winsz) < 0) { /* old seventies way of getting the screen size */ if (screen_cols == 0 && (screen_cols = tgetnum ("co")) == -1) screen_cols = DEFAULT_COLS; if (screen_rows == 0 && (screen_rows = tgetnum ("li")) == -1) screen_rows = DEFAULT_ROWS; } else { /* sparkly new way -- ap1i */ screen_cols = winsz.ws_col; if (screen_cols <= 0) screen_cols = DEFAULT_COLS; screen_rows = winsz.ws_row; if (screen_rows <= 0) screen_rows = DEFAULT_ROWS; } if (*MD == '\0' || *ME == '\0' || *MR == '\0') { MD = SO; ME = SE; MR = SO; } if (*UE == '\0' || *US == '\0') { UE = SE; US = SO; } screen_inited = 1; tputs (TI, 1, outc); clear_screen (); row = screen_rows / 2; col = (screen_cols - (sizeof ("The story is loading...") - 1)) / 2; move_cursor (row, col); display_string ("The story is loading..."); h_interpreter = INTERP_MSDOS; set_cbreak_mode (1); }/* initialize_screen */ void restart_screen () { cursor_saved = OFF; if (h_type < V4) set_byte (H_CONFIG, (get_byte (H_CONFIG) | CONFIG_WINDOWS)); else set_byte (H_CONFIG, (get_byte (H_CONFIG) | CONFIG_EMPHASIS | CONFIG_WINDOWS)); /* Force graphics off as we can't do them */ set_word (H_FLAGS, (get_word (H_FLAGS) & (~GRAPHICS_FLAG))); }/* restart_screen */ void reset_screen () { if (!screen_inited) return; delete_status_window (); select_text_window (); set_attribute (NORMAL); set_cbreak_mode (0); tputs (TE, 1, outc); screen_inited = 0; }/* reset_screen */ void clear_screen () { tputs (CL, 1, outc); current_row = 1; current_col = 1; }/* clear_screen */ void select_status_window () { save_cursor_position (); }/* select_status_window */ void select_text_window () { restore_cursor_position (); }/* select_text_window */ void create_status_window () { int row, col; if (*CS) { get_cursor_position (&row, &col); tputs (tgoto (CS, screen_rows - 1, status_size), 1, outc); move_cursor (row, col); } }/* create_status_window */ void delete_status_window () { int row, col; if (*CS) { get_cursor_position (&row, &col); tputs (tgoto (CS, screen_rows - 1, 0), 1, outc); move_cursor (row, col); } }/* delete_status_window */ void clear_line () { tputs (CE, 1, outc); }/* clear_line */ void clear_text_window () { int i, row, col; get_cursor_position (&row, &col); for (i = status_size + 1; i <= screen_rows; i++) { move_cursor (i, 1); clear_line (); } move_cursor (row, col); }/* clear_text_window */ void clear_status_window () { int i, row, col; get_cursor_position (&row, &col); for (i = status_size; i; i--) { move_cursor (i, 1); clear_line (); } move_cursor (row, col); }/* clear_status_window */ void move_cursor (row, col) int row; int col; { tputs (tgoto (CM, col - 1, row - 1), 1, outc); current_row = row; current_col = col; }/* move_cursor */ void get_cursor_position (row, col) int *row; int *col; { *row = current_row; *col = current_col; }/* get_cursor_position */ void save_cursor_position () { if (cursor_saved == OFF) { get_cursor_position (&saved_row, &saved_col); cursor_saved = ON; } }/* save_cursor_position */ void restore_cursor_position () { if (cursor_saved == ON) { move_cursor (saved_row, saved_col); cursor_saved = OFF; } }/* restore_cursor_position */ void set_attribute (attribute) int attribute; { if (attribute == NORMAL) { tputs (ME, 1, outc); tputs (UE, 1, outc); } if (attribute & REVERSE) tputs (MR, 1, outc); if (attribute & BOLD) tputs (MD, 1, outc); if (attribute & EMPHASIS) tputs (US, 1, outc); if (attribute & FIXED_FONT) ; }/* set_attribute */ static void display_string (s) char *s; { while (*s) display_char (*s++); }/* display_string */ void display_char (c) int c; { outc (c); if (++current_col > screen_cols) current_col = screen_cols; }/* display_char */ void scroll_line () { int row, col; get_cursor_position (&row, &col); if (*CS || row < screen_rows) { display_char ('\n'); } else { move_cursor (status_size + 1, 1); tputs (DL, 1, outc); move_cursor (row, 1); } current_col = 1; if (++current_row > screen_rows) current_row = screen_rows; }/* scroll_line */ int input_character (timeout) int timeout; { struct timeval tv; struct timezone tz; gettimeofday (&tv, &tz); tv.tv_sec += timeout; fflush (stdout); if (timeout && wait_for_char (&tv)) return (-1); return (read_key ()); }/* input_character */ int input_line (buflen, buffer, timeout, read_size) int buflen; char *buffer; int timeout; int *read_size; { struct timeval tv; struct timezone tz; int c, row, col; gettimeofday (&tv, &tz); tv.tv_sec += timeout; for ( ; ; ) { /* Read a single keystroke */ fflush (stdout); if (timeout && wait_for_char (&tv)) return (-1); c = read_key (); if (c == '\b') { /* Delete key action */ if (*read_size == 0) { /* Ring bell if line is empty */ outc (BELL); } else { /* Decrement read count */ (*read_size)--; /* Erase last character typed */ get_cursor_position (&row, &col); move_cursor (row, --col); display_char (' '); move_cursor (row, col); } } else { /* Normal key action */ if (*read_size == (buflen - 1)) { /* Ring bell if buffer is full */ outc (BELL); } else { /* Scroll line if return key pressed */ if (c == '\n') { scroll_line (); return (c); } else { /* Put key in buffer and display it */ buffer[(*read_size)++] = (char) c; display_char (c); } } } } }/* input_line */ static int wait_for_char (timeout) struct timeval *timeout; { int nfds, status; fd_set readfds; struct timeval tv; struct timezone tz; gettimeofday (&tv, &tz); if (tv.tv_sec >= timeout->tv_sec && tv.tv_usec >= timeout->tv_usec) return (-1); tv.tv_sec = timeout->tv_sec - tv.tv_sec; if (timeout->tv_usec < tv.tv_usec) { tv.tv_sec--; tv.tv_usec = (timeout->tv_usec + 1000000) - tv.tv_usec; } else tv.tv_usec = timeout->tv_usec - tv.tv_usec; nfds = getdtablesize (); FD_ZERO (&readfds); FD_SET (fileno (stdin), &readfds); status = select (nfds, &readfds, NULL, NULL, &tv); if (status < 0) { perror ("select"); return (-1); } if (status == 0) return (-1); else return (0); }/* wait_for_char */ static int read_key () { int c; c = getchar (); if (c == 127) c = '\b'; else if (c == '\r') c = '\n'; return (c); }/* read_key */ static void set_cbreak_mode (mode) int mode; { int status; #if defined(BSD) struct sgttyb new_tty; static struct sgttyb old_tty; #endif /* defined(BSD) */ #if defined(SYSTEM_FIVE) struct termio new_termio; static struct termio old_termio; #endif /* defined(SYSTEM_FIVE) */ #if defined(POSIX) struct termios new_termios; static struct termios old_termios; #endif /* defined(POSIX) */ #if defined(BSD) status = ioctl (fileno (stdin), (mode) ? TIOCGETP : TIOCSETP, &old_tty); #endif /* defined(BSD) */ #if defined(SYSTEM_FIVE) status = ioctl (fileno (stdin), (mode) ? TCGETA : TCSETA, &old_termio); #endif /* defined(SYSTEM_FIVE) */ #if defined(POSIX) if (mode) status = tcgetattr (fileno (stdin), &old_termios); else status = tcsetattr (fileno (stdin), TCSANOW, &old_termios); #endif /* defined(POSIX) */ if (status) { perror ("ioctl"); exit (1); } if (mode) { signal (SIGINT, rundown); signal (SIGTERM, rundown); } if (mode) { #if defined(BSD) status = ioctl (fileno (stdin), TIOCGETP, &new_tty); #endif /* defined(BSD) */ #if defined(SYSTEM_FIVE) status = ioctl (fileno (stdin), TCGETA, &new_termio); #endif /* defined(SYSTEM_FIVE) */ #if defined(POSIX) status = tcgetattr (fileno (stdin), &new_termios); #endif /* defined(POSIX) */ if (status) { perror ("ioctl"); exit (1); } #if defined(BSD) new_tty.sg_flags |= CBREAK; new_tty.sg_flags &= ~ECHO; #endif /* defined(BSD) */ #if defined(SYSTEM_FIVE) new_termio.c_lflag &= ~(ICANON | ECHO); #endif /* defined(SYSTEM_FIVE) */ #if defined(POSIX) new_termios.c_lflag &= ~(ICANON | ECHO); #endif /* defined(POSIX) */ #if defined(BSD) status = ioctl (fileno (stdin), TIOCSETP, &new_tty); #endif /* defined(BSD) */ #if defined(SYSTEM_FIVE) status = ioctl (fileno (stdin), TCSETA, &new_termio); #endif /* defined(SYSTEM_FIVE) */ #if defined(POSIX) status = tcsetattr (fileno (stdin), TCSANOW, &new_termios); #endif /* defined(POSIX) */ if (status) { perror ("ioctl"); exit (1); } } if (mode == 0) { signal (SIGINT, SIG_DFL); signal (SIGTERM, SIG_DFL); } }/* set_cbreak_mode */ static void rundown () { unload_cache (); close_story (); close_script (); reset_screen (); }/* rundown */ xzip/variable.c0100600000076400007640000000404306551763103012477 0ustar zarfzarf/* * variable.c * * Variable manipulation routines * */ #include "ztypes.h" /* * load * * Load and store a variable value. * */ #ifdef __STDC__ void load (zword_t variable) #else void load (variable) zword_t variable; #endif { store_operand (load_variable (variable)); }/* load */ /* * push_var * * Push a value onto the stack * */ #ifdef __STDC__ void push_var (zword_t value) #else void push_var (value) zword_t value; #endif { stack[--sp] = value; }/* push_var */ /* * pop_var * * Pop a variable from the stack. * */ #ifdef __STDC__ void pop_var (zword_t variable) #else void pop_var (variable) zword_t variable; #endif { store_variable (variable, stack[sp++]); }/* pop_var */ /* * increment * * Increment a variable. * */ #ifdef __STDC__ void increment (zword_t variable) #else void increment (variable) zword_t variable; #endif { store_variable (variable, load_variable (variable) + 1); }/* increment */ /* * decrement * * Decrement a variable. * */ #ifdef __STDC__ void decrement (zword_t variable) #else void decrement (variable) zword_t variable; #endif { store_variable (variable, load_variable (variable) - 1); }/* decrement */ /* * increment_check * * Increment a variable and then check its value against a target. * */ #ifdef __STDC__ void increment_check (zword_t variable, zword_t target) #else void increment_check (variable, target) zword_t variable; zword_t target; #endif { short value; value = (short) load_variable (variable); store_variable (variable, ++value); conditional_jump (value > (short) target); }/* increment_check */ /* * decrement_check * * Decrement a variable and then check its value against a target. * */ #ifdef __STDC__ void decrement_check (zword_t variable, zword_t target) #else void decrement_check (variable, target) zword_t variable; zword_t target; #endif { short value; value = (short) load_variable (variable); store_variable (variable, --value); conditional_jump (value < (short) target); }/* decrement_check */ xzip/quetzal.c0100640000076400007640000004174406551763103012414 0ustar zarfzarf/* quetzal.c * * routines to handle QUETZAL save format */ #include #include #include "ztypes.h" /* You may want to define these as getc and putc, but then the code gets * quite big (especially for put_c). */ #define get_c fgetc #define put_c fputc #ifndef SEEK_CUR #define SEEK_CUR 1 #endif #if defined(USE_QUETZAL) /* don't compile anything otherwise */ typedef unsigned long ul_t; #define makeid(a,b,c,d) ((ul_t)(((a)<<24) | ((b)<<16) | ((c)<<8) | (d))) /* IDs of chunks we understand */ #define ID_FORM makeid('F','O','R','M') #define ID_IFZS makeid('I','F','Z','S') #define ID_IFhd makeid('I','F','h','d') #define ID_UMem makeid('U','M','e','m') #define ID_CMem makeid('C','M','e','m') #define ID_Stks makeid('S','t','k','s') #define ID_ANNO makeid('A','N','N','O') /* macros to write QUETZAL files */ #define write_byte(fp,b) (put_c (b,fp) != EOF) #define write_bytx(fp,b) write_byte(fp,(b) & 0xFF) #define write_word(fp,w) \ (write_bytx(fp,(w)>> 8) && write_bytx(fp,(w))) #define write_long(fp,l) \ (write_bytx(fp,(l)>>24) && write_bytx(fp,(l)>>16) && \ write_bytx(fp,(l)>> 8) && write_bytx(fp,(l))) #define write_chnk(fp,id,len) \ (write_long(fp,id) && write_long(fp,len)) #define write_run(fp,run) \ (write_byte(fp,0) && write_byte(fp,(run))) /* save_quetzal * * attempt to save game in QUETZAL format; return TRUE on success */ #if defined(__STDC__) int save_quetzal (FILE *sfp, FILE *gfp, long zoffset) #else int save_quetzal (sfp,gfp,zoffset) FILE *sfp,*gfp; long zoffset; #endif { ul_t ifzslen = 0, cmemlen = 0, stkslen = 0, tmp_pc; int c; zword_t i, j, n, init_fp, tmp_fp, nstk, nvars, args; zword_t frames[STACK_SIZE/4+1]; zbyte_t var; long cmempos,stkspos; /* write IFZS header */ if (!write_chnk(sfp,ID_FORM,0)) return FALSE; if (!write_long(sfp,ID_IFZS)) return FALSE; /* write IFhd chunk */ if (!write_chnk(sfp,ID_IFhd,13)) return FALSE; if (!write_word(sfp,h_version)) return FALSE; for (i=0; i<6; ++i) if(!write_byte(sfp,get_byte(H_RELEASE_DATE+i))) return FALSE; if (!write_word(sfp,h_checksum)) return FALSE; if (!write_long(sfp,pc<<8)) /* includes pad byte */ return FALSE; /* write CMem chunk */ /* j is current run length */ if ((cmempos = ftell(sfp)) < 0) return FALSE; if (!write_chnk(sfp,ID_CMem,0)) return FALSE; fseek (gfp, zoffset, SEEK_SET); for (i=0, j=0, cmemlen=0; i < h_restart_size; ++i) { if ((c = get_c (gfp)) == EOF) return FALSE; c ^= get_byte (i); if(c == 0) ++j; else { /* write any run there may be */ if (j > 0) { for (; j > 0x100; j -= 0x100) { if (!write_run(sfp,0xFF)) return FALSE; cmemlen += 2; } if (!write_run(sfp,j-1)) return FALSE; cmemlen += 2; j = 0; } /* write this byte */ if (!write_byte(sfp,c)) return FALSE; ++cmemlen; } } /* there may be a run here, which we ignore */ if (cmemlen & 1) /* chunk length must be even */ if (!write_byte(sfp,0)) return FALSE; /* write Stks chunk */ if ((stkspos = ftell(sfp)) < 0) return FALSE; if (!write_chnk(sfp,ID_Stks,0)) return FALSE; /* frames is a list of FPs, most recent first */ frames[0] = sp-5; /* what FP would be if we did a call now */ for (init_fp=fp, n=0; init_fp <= STACK_SIZE-5; init_fp=stack[init_fp+2]) { frames[++n] = init_fp; } init_fp = frames[n] + 4; if (h_type != 6) { /* write a dummy frame for stack used before first call */ for (i = 0; i < 6; ++i) if (!write_byte(sfp,0)) return FALSE; nstk = STACK_SIZE - 1 - init_fp; if (!write_word(sfp,nstk)) return FALSE; for(i = STACK_SIZE-1; i > init_fp; --i) if (!write_word(sfp,stack[i])) return FALSE; stkslen = 8 + 2*nstk; } for (i=n; i>0; --i) { /* write out one stack frame. * * tmp_fp : FP when this frame was current * tmp_pc : PC on return from this frame, plus 000pvvvv * nvars : number of local vars for this frame * args : argument mask for this frame * nstk : words of evaluation stack used for this frame * var : variable to store result */ tmp_fp = frames[i]; nvars = (stack[tmp_fp+1] & VARS_MASK) >> VAR_SHIFT; args = stack[tmp_fp+1] & ARGS_MASK; nstk = tmp_fp - frames[i-1] - nvars - 4; tmp_pc = stack[tmp_fp+3] + (ul_t) stack[tmp_fp+4]*PAGE_SIZE; switch(stack[tmp_fp+1] & TYPE_MASK) { case FUNCTION: var = read_data_byte (&tmp_pc); /* also increments tmp_pc */ tmp_pc = (tmp_pc << 8) | nvars; break; case PROCEDURE: var = 0; tmp_pc = (tmp_pc << 8) | 0x10 | nvars; /* set procedure flag */ break; /* case ASYNC: */ default: output_line ("Illegal Z-machine operation: can't save while in interrupt."); return FALSE; } if (args != 0) args = (1 << args)-1; /* make args into bitmap */ if (!write_long(sfp,tmp_pc)) return FALSE; if (!write_byte(sfp,var)) return FALSE; if (!write_byte(sfp,args)) return FALSE; if (!write_word(sfp,nstk)) return FALSE; for (j=0; j 0) { /* read chunk header */ if (ifzslen < 8) return FALSE; if (!read_long(sfp,&tmpl) || !read_long(sfp,&currlen)) return FALSE; ifzslen -= 8; /* body of chunk */ if (ifzslen < currlen) return FALSE; skip = currlen & 1; ifzslen -= currlen+skip; switch (tmpl) { case ID_IFhd: if (progress & GOT_HEADER) { output_line ("Save file has two IFhd chunks!"); return FALSE; } progress |= GOT_HEADER; if (currlen < 13 || !read_word (sfp,&i)) return FALSE; if (i != h_version) progress = GOT_ERROR; for (i=H_RELEASE_DATE; i 0; currlen-=8) { if (currlen < 8) return FALSE; if (sp<4) { output_line ("error: this save-file has too much stack, and I can't cope."); return FALSE; } /* read PC, procedure flag, and arg count */ if (!read_long(sfp,&tmpl)) return FALSE; y = (zword_t) tmpl & 0x0F; tmpw = y << VAR_SHIFT; /* number of variables */ /* read result variable */ if ((x = get_c (sfp)) == EOF) return FALSE; if (tmpl & 0x10) { tmpw |= PROCEDURE; tmpl >>= 8; } else { tmpw |= FUNCTION; tmpl >>= 8; --tmpl; /* sanity check on result variable */ if (read_data_byte (&tmpl) != (zbyte_t) x) { output_line ("error: wrong variable number on stack (wrong story file?)."); return FALSE; } --tmpl; /* read_data_byte increments it */ } stack[--sp] = (zword_t) (tmpl / PAGE_SIZE); stack[--sp] = (zword_t) (tmpl % PAGE_SIZE); stack[--sp] = fp; if ((x = get_c (sfp)) == EOF) return FALSE; ++x; /* hopefully x now contains a single set bit */ for (i=0; i<8; ++i) if (x & (1<=sp) { output_line ("error: this save-file uses more stack than I can cope with."); return FALSE; } if (currlen < tmpw*2) return FALSE; for (i=0; i 0; --currlen) { if ((x = get_c (sfp)) == EOF) return FALSE; else write_char (x); } write_char ((char) 13); break; */ case ID_CMem: if (!(progress & GOT_MEMORY)) { fseek (gfp, zoffset, SEEK_SET); i=0; /* bytes written to data area */ for (; currlen > 0; --currlen) { if ((x = get_c (sfp)) == EOF) return FALSE; if (x == 0) /* start run */ { if (currlen < 2) { output_line ("File contains bogus CMem chunk"); for (; currlen > 0; --currlen) (void) get_c (sfp); /* skip rest */ currlen = 1; i = 0xFFFF; break; /* keep going in case there's a UMem */ } --currlen; if ((x = get_c (sfp)) == EOF) return FALSE; for (; x>=0 && ih_restart_size) { output_line ("warning: CMem chunk too long!"); for (; currlen > 1; --currlen) (void) get_c (sfp); /* skip rest */ break; /* keep going in case there's a UMem */ } } /* if chunk is short, assume a run */ for (; i