! ---------------------------------------------------------------------------- ! ZEDIT ! The World's Most Portable Text Editor ! Copyright 1997 Charles Briscoe-Smith ! $Id: zedit.inf,v 1.4 1997/11/02 19:35:05 cpb4 Exp $ ! ---------------------------------------------------------------------------- ! Redistribution and use in source code and/or executable forms, with ! or without modification, are permitted provided that the following ! condition is met: ! ! Any redistribution must retain the above copyright notice, this ! condition and the following disclaimer, either as part of the program ! source code included in the redistribution or in human-readable ! materials provided with the redistribution. ! ! THIS SOFTWARE IS PROVIDED "AS IS". Any express or implied warranties ! concerning this software are disclaimed by the copyright holder to ! the fullest extent permitted by applicable law. In no event shall the ! copyright-holder be liable for any damages of any kind, however caused ! and on any theory of liability, arising in any way out of the use of, ! or inability to use, this software. ! ---------------------------------------------------------------------------- ! In other words, do not misrepresent my work as your own work, and do ! not sue me if it causes problems. Feel free to do anything else you ! wish with it! ! ---------------------------------------------------------------------------- ! ---------------------------------------------------------------------------- ! By the way, I also ask that you do not misrepresent your work as mine! ! If you make changes to this program, please add an entry to the ! changelog. ! ! $Log: zedit.inf,v $ ! Revision 1.4 1997/11/02 19:35:05 cpb4 ! Bumped up version number to 0.1 ! Wrote ShowErrorS and ShowErrorSN. ! Fixed redraw bug: screen was not redrawing automatically after ! redraw_timeout deciseconds. ! LoadFile and SaveFile now show error messages when appropriate. ! ! Revision 1.3 1997/10/27 12:14:10 cpb4 ! In comments, made distinction between document cursor and screen cursor. ! Split ReadKeyWithTimeout() out of DoKey; put it in "keyboard" section. ! Add ClearFile() and DeleteChar(). ! Move necessary screen management into BringInFile() and SendOutFile(). ! Add lots more comments. ! New section, "on-screen window", to collect window-management code. ! Cleaned up "display-related state"; separated cache from non-cache. ! Renamed RecalculateLinePos() to RefreshCache() and updated it. ! Renamed many globals to better describe their function. ! Started adding Invalidate*() functions for cache managment. ! Changed background outside of the document to dots instead of spaces. ! Wrote RetreatOneScreenLine(). ! Put statistics display into the top border. ! Added NeedRedraw(). ! Updated scrolling code. ! ! Revision 1.2 1997/10/24 11:01:42 cpb4 ! Added lots of comments. ! Wrote InRange() to compare addresses (Thanks due to Graham Nelson ! for writing UnsignedCompare in the Inform library's parserm.h, ! and to Andrew Plotkin for pointing it out to me.) ! Updated memory management code to use InRange. ! Bumped total_memory_size up to 60,000. ! Simplified and rewrote RetreatOneLine. ! In LoadFile and SaveFile, removed the text "enter a filename"; the ! interpreter should take care of prompting the user as necessary. ! ! Revision 1.1 1997/10/23 14:21:25 cpb4 ! Initial revision ! ---------------------------------------------------------------------------- ! ---------------------------------------------------------------------------- ! Preliminaries ! ! This is a version 5 "story"-file. It uses features not available in ! version 3, but isn't big enough (yet) to warrant being version 8. Switches v5; ! This program is still very much alpha quality, hence the version number. Constant ZEdit_Version="0.1"; ! ---------------------------------------------------------------------------- ! Screen modes and setup ! ! The Z machine has two output windows; prose output in the main ! window, and character-cell output in the status line. Since we want ! character-cell output, we'll only be using the status line. It'll have ! to be expanded to a reasonable size first. ! ! We'll need to know how big the screen is. From ZEdit's perspective, ! each character cell on the screen has a pair of coordinates, ranging ! on the x-axis from 0 to scr_xmax, and on the y-axis from 0 to scr_ymax. Global scr_xmax; Global scr_ymax; ! When the program starts, OpenScreen expands the status line to full ! screen size and initialises scr_xmax and scr_ymax. [ OpenScreen; ! Fetch the width and maximum height of the status line from the ! story-file header. scr_xmax=(0->33); scr_ymax=(0->32); if (scr_xmax<80 || scr_ymax<24) { print "^^ Warning^ -------^ ^ ZEdit has not yet been tested with screens this small. You my find that things break in unexpected ways. Please report anything you think could be corrected to .^ ^ [Press any key to continue...]"; ReadKey(); } ! Switch to character-cell mode. @erase_window -1; @split_window scr_ymax; @set_window 1; @buffer_mode 0; @set_cursor 1 1; ! Transform width and height into maximum x and y ordinates. scr_xmax--; scr_ymax--; ]; ! When we load or save a file, we must switch to the prose window so ! that the interpreter can ask the user for a filename without messing ! up the screen. When we do this, HalfScreen contracts the status line ! to cover just half the screen. [ HalfScreen i; i=scr_ymax/2; @buffer_mode 1; @set_window 0; @split_window i; @erase_window 0; ]; ! FullScreen undoes the effects of HalfScreen. [ FullScreen i; i=scr_ymax+1; @erase_window 0; @split_window i; @set_window 1; @buffer_mode 0; @set_cursor 1 1; ]; ! CloseScreen switches the screen back to prose mode so that the program ! can quit nicely. [ CloseScreen; @buffer_mode 1; @set_window 0; @split_window 0; @erase_window -1; ]; ! ---------------------------------------------------------------------------- ! Screen cursor movement and output primitives ! ! We want to be able to output text at given positions on the screen. ! These functions allow that. Note that they manipulate the screen ! cursor, not the document cursor (explained later). ! ! GoTo moves the screen cursor. We have to convert ZEdit's 0-based ! coordinates to Z machine 1-based coordinates. [ GoTo x y; if (x<=scr_xmax) x++; y++; @set_cursor y x; ]; ! AtScreen prints a string at given coordinates. [ AtScreen x y string; GoTo(x, y); print (string) string; ]; ! ParkCursor moves the screen cursor to an out-of-the-way part of ! the screen. [ ParkCursor; GoTo(0, scr_ymax); ]; ! HLine draws a horizontal line of Cs from X1,Y to X2,Y [ HLine x1 x2 y c i; GoTo(x1, y); for (i=x1:i<=x2:i++) { print (char) c; } ]; ! VLine draws a vertical line of Cs from X,Y1 to X,Y2 [ VLine x y1 y2 c i; for (i=y1:i<=y2:i++) { GoTo(x, i); print (char) c; } ]; ! Box draws a hollow frame of inverse spaces and clears the space within. [ Box x1 y1 x2 y2 i; style reverse; HLine(x1, x2, y1, ' '); VLine(x1, y1+1, y2-1, ' '); VLine(x2, y1+1, y2-1, ' '); HLine(x1, x2, y2, ' '); style roman; for (i=y1+1:i key; return key; ]; ! KeyInterrupt is a utility function used in ReadKeyWithTimeout. [ KeyInterrupt; rtrue; ]; ! ReadKeyWithTimeout reads a character from the keyboard and returns ! its code, as ReadKey does. If time/10 seconds elapse first, though, ! it returns 0. This implies that 0 cannot be a valid character code, ! and this is indeed the case. [ ReadKeyWithTimeout time key; @read_char 1 time KeyInterrupt -> key; return key; ]; ! ---------------------------------------------------------------------------- ! CantHappen quits the program when something awful happens, informing ! the user of the reason. [ CantHappen str; print "^*** ", (string) str, " ***^"; quit; ]; ! InRange takes an address and a "range" (one greater than the maximum ! address) and checks that the number is in the range. Effectively this ! is an unsigned comparison on signed numbers. Thanks to Graham Nelson ! for writing UnsignedCompare in the Inform library's parserm.h, and to ! Andrew Plotkin for pointing it out to me. [ InRange n r; if ((n>=0 && r>=0) || (n<0 && r<0)) return n=0) rtrue; rfalse; ]; ! ---------------------------------------------------------------------------- ! Memory management ! ! Since ZEdit is written in Inform, it is targeted at the Z machine. ! Since the Z machine architecture imposes an upper limit of 64 kilobytes ! on the size of a program's modifiable data, an overriding design goal of ! ZEdit is to allow the user as much of this space as possible to work in. ! ! The Z machine does not (as far as I know) possess opcodes allowing ! segments of files to be read in and written out; if it did, we could ! page the text file into the Z machine's data segment. ! ! Memory management will be based around a big array called "memory". ! total_memory_size is the size of this array. Since we may want to ! carve chunks off the end of memory and use them for other things (like ! copy buffers, say) document_memory_size indicates how much memory is ! left for the document. Constant total_memory_size=60000; Array memory -> total_memory_size; Global document_memory_size=total_memory_size; ! The user's current position in the file is represented by the document ! cursor (distinct from the screen cursor, although we leave the screen ! cursor indicating the document cursor's position whenever possible). ! ! We will use a sneaky method of ensuring that we don't have to copy ! the whole file whenever the user wants to insert a character near ! its beginning. The text will be divided into two chunks at the ! document cursor position. All text before the document cursor is ! stored at the start of the memory, and the rest is stored at the end. ! These two variables keep track of how big each chunk is. The first ! of these gives the offset of the document cursor into the file, as ! well as the size of the first chunk, and is named accordingly. Global cursor_address; Global chars_after_cursor; ! ClearFile resets the editor to its starting state: editing a blank ! document. [ ClearFile; cursor_address=0; chars_after_cursor=0; ]; ! InsertChar places a given character into the text at the current ! document cursor position. Since we are keeping the text in two chunks ! as described above, we can do this by simply writing the character to ! memory and incrementing a pointer. We check that this won't fill up ! memory first, though. InsertChar returns true if the character was ! inserted, false otherwise. [ InsertChar c; if (~~InRange(cursor_address+chars_after_cursor, document_memory_size)) rfalse; memory->cursor_address=c; cursor_address++; rtrue; ]; ! DeleteChar removes the character before the current cursor position ! and closes up the gap. It returns true if a character was deleted, ! false otherwise. [ DeleteChar; if (cursor_address==0) rfalse; cursor_address--; rtrue; ]; ! SetCursorAddress is used to reposition the document cursor. This is ! where we shuffle bytes between the two chunks and adjust the chunk ! sizes to match. A position of 0 means before first character of the ! document, a position equal to the number of characters means after ! the last character. [ SetCursorAddress pos len src dest; len=cursor_address+chars_after_cursor; if (~~InRange(pos, len+1)) CantHappen("Illegal call to SetCursorAddress"); if (pos==cursor_address) return; if (InRange(pos, cursor_address)) { ! Copy some stuff to the final segment. src=cursor_address-1; dest=document_memory_size-chars_after_cursor-1; for (len=cursor_address-pos: len~=0: len--) { memory->dest=memory->src; dest--; src--; } } else { ! Copy some stuff to the initial segment. src=document_memory_size-chars_after_cursor; dest=cursor_address; for (len=pos-cursor_address: len~=0: len--) { memory->dest=memory->src; dest++; src++; } } chars_after_cursor=chars_after_cursor+(cursor_address-pos); cursor_address=pos; ]; ! PeekChar allows characters to be read from memory, while giving the ! illusion that the text is stored contiguously. By doing some pointer ! arithmetic, we read the requested character from the appropriate chunk. [ PeekChar pos; if (InRange(pos, cursor_address)) { return (memory->pos); } else if (InRange(pos, cursor_address+chars_after_cursor)) { return (memory->(document_memory_size-chars_after_cursor +pos-cursor_address)); } else { return -1; } ]; ! BringInFile loads a file into memory. The default filename must have ! already been set up before this routine is called; we simply read ! the file in and set up pointers appropriately. The document cursor ! is set to the start of the file if the file is read in correctly. ! We return 1 if the file was read in okay, -1 if there was an error ! caught by the Z machine, or -2 if the file was too large to fit in ! our limited memory space. ! ! We can detect this last condition by allowing the Z machine to read in ! up to the total amount of memory available. If this space is filled, ! the file was too big. Normally, ZEdit never handles files larger than ! one byte less than its total memory space. ! ! This routine must set the screen to prose mode before calling @restore, ! and restore it to full screen afterwards, so that the Z machine can ! ask the user for a filename, if it wants to. [ BringInFile filename size; HalfScreen(); print "^Loading file...^"; @restore memory document_memory_size filename -> size; FullScreen(); if (size==0) { return -1; } else if (size==document_memory_size) { ClearFile(); return -2; } else { cursor_address=size; chars_after_cursor=0; SetCursorAddress(0); return 1; } ]; ! When we save the file, all the text must be in one contiguous block. ! Consolidate arranges this. [ Consolidate; SetCursorAddress(cursor_address+chars_after_cursor); ]; ! SendOutFile saves the file. The default filename must have already ! been set up before this routine is called; we simply write the file out. ! We return 1 if the file was written out okay, or 0 if there was an error ! caught by the Z machine. We also ensure that the document cursor does ! not move when this routine is called. ! ! This routine must set the screen to prose mode before calling @save, ! and restore it to full screen afterwards, so that the Z machine can ! ask the user for a filename, if it wants to. [ SendOutFile filename cursorpos retval; cursorpos=cursor_address; Consolidate(); HalfScreen(); print "^Saving file...^"; @save memory cursor_address filename -> retval; FullScreen(); SetCursorAddress(cursorpos); return retval; ]; ! ---------------------------------------------------------------------------- ! On-screen window ! ! In preparation for the next section, we now define the window on the ! screen which will contain the displayed document text. The screen modes ! and setup section above keeps track of the size of the whole screen, ! but we will not be using all of it for displaying text; the screen ! borders will contain (hopefully) helpful information for the user. Constant TOP_MARGIN=1; Constant BOTTOM_MARGIN=1; Constant LEFT_MARGIN=0; Constant RIGHT_MARGIN=0; ! These two variables will indicate how big the text window is; to ! position the screen cursor in this window, we have to take TOP_MARGIN ! and LEFT_MARGIN into account. Global window_width; Global window_height; ! Since the Z machine does not have the capacity to scroll the status ! window, the whole window must be redrawn whenever a scroll would ! otherwise take place. Since this could be very slow for a large window, ! we'd like the screen to scroll by several lines at once. scroll_quantum ! is the minimum number of lines which will be scrolled at any one time. Global scroll_quantum; ! WindowInit sets up the on-screen window when ZEdit starts. [ WindowInit; window_height=scr_ymax+1-TOP_MARGIN-BOTTOM_MARGIN; window_width=scr_xmax+1-LEFT_MARGIN-RIGHT_MARGIN; scroll_quantum=(window_height+1)/2; ]; ! ---------------------------------------------------------------------------- ! Display-related state ! ! Keeping track of how the file is being displayed on the screen at the ! current moment, and working out a reasonably optimal way to correctly ! update the display is tedious and error-prone at best. Physical lines ! in the file are delimited in different ways by different operating ! systems, and in any case do not usually correspond one-to-one to ! lines on the screen. ZEdit will keep track of its current posision ! in several ways, for several different purposes. ! ! One way we keep track of positions is in terms of physical, ! newline-terminated lines in the file. It should be noted that the ! _concept_ of a "newline" is operating-system independent, while the ! sequence of character codes which realise a newline depend on the ! particular system in use: on UNIX, a newline is an ASCII linefeed; on ! DOS, it's a carriage return-linefeed pair; on Macintosh (as I understand ! it), it's just a carriage return. Some systems, like VMS, don't even ! store newlines, prefering them to exist only implicitly between lines ! stored in a database-line record structure. ZEdit doesn't even attempt ! to handle VMS-like file structures. ! ! The physical line number of the first line in the file is 1, to match ! the error messages given by most compilers. (When the user enters ! a line number, for instance when requesting to jump directly to that ! line, 0 will be used to indicate the _last_ line in the file.) ! ! In order to display the file on the screen, these physical lines ! have to be chopped up into logical lines. This gives a long "scroll" ! of logical lines, of which we display a window-full at a time. ! ! To make matters worse, not all characters in the file are directly ! displayable on the screen. Some will therefore have to be displayed as ! sequences of displayable characters. For example, a Control-A (ASCII ! code 1) may be displayed as the two characters "^A". The width of a ! character's display representation may even change depending on where ! it is printed: a TAB (ASCII 9) is usually displayed as a sequence of ! spaces, the number of which is calculated to ensure the next character ! is displayed at the next tab stop. ! ! We need to keep track of several things. The address of the character ! at the top-left of the screen gives us the ability to work out ! exactly what section of the file is being displayed on the screen ! at any particular moment. This address should always correspond to ! the beginning of a logical line. We already have the address of the ! document cursor; that's stored in the memory management section. Global screen_start_address; !Global cursor_address; ! From these two, we can work out everything else we need, but this ! would be terribly slow. There are many bits of data which can be ! derived from these that we want access to fairly frequently, and so ! we should work them out only when necessary and cache the results. ! ! First up is the physical line number corresponding to ! screen_start_address. Since screen_start_address is not necessarily ! positioned at the start of a physical line, the value stored here is ! the number of the line screen_start_address is on. Global screen_start_physical_y; ! Next, we'd like to know the start of the physical line the cursor is ! currently on: its address, its physical line number, and its y ordinate ! within the on-screen window. Global physical_line_start_address; Global physical_line_number; Global physical_line_start_window_y; ! And, in case the cursor is not on the first logical line of its ! physical line, we'd like the same information for the logical line ! (minus the line number). Global logical_line_start_address; Global logical_line_start_window_y; ! ********** Here endeth the documentation (for now) ************************* ! Window-relative coordinates of cursor_address Global cursor_window_x; ! The last value of cursor_window_x set by explicit horizontal movement Global cursor_ideal_x; [ InvalidateIdealX; cursor_ideal_x=-1; ]; ! ---------------------------------------------------------------------------- [ RefreshCache physlinepos physlineno physliney loglinepos logliney curpos curx j; ! If the cursor has moved off the top of the screen, indicate so, ! and don't try to work anything else out. if (~~InRange(screen_start_address, cursor_address+1)) { logical_line_start_window_y=-1; return; } if (physical_line_start_address~=-1 && InRange(physical_line_start_address, cursor_address+1)) { ! If we know where this physical line starts, recalculate from there. curpos=physical_line_start_address; curx=0; physlinepos=physical_line_start_address; physlineno=physical_line_number; physliney=physical_line_start_window_y; loglinepos=physical_line_start_address; logliney=physical_line_start_window_y; } else { ! Otherwise, give up and recalculate everything. ! screen_start_physical_y is never recalculated, since it should be ! updated whenever screen_start_address is changed. curpos=screen_start_address; curx=0; physlinepos=screen_start_address; physlineno=screen_start_physical_y; physliney=0; loglinepos=screen_start_address; logliney=0; } while (InRange(curpos, cursor_address)) { j=PeekChar(curpos++); curx=curx+PrintWidth(j, curx); if (curx>window_width) { curx=PrintWidth(j, 0); loglinepos=curpos-1; logliney++; } if (j==ASCII_LF) { curx=0; loglinepos=curpos; logliney++; physlinepos=curpos; physlineno++; physliney=logliney; } if (curx==window_width) { curx=0; loglinepos=curpos; logliney++; } } physical_line_start_address=physlinepos; physical_line_number=physlineno; physical_line_start_window_y=physliney; logical_line_start_address=loglinepos; logical_line_start_window_y=logliney; cursor_window_x=curx; if (cursor_ideal_x==-1) cursor_ideal_x=((logical_line_start_window_y -physical_line_start_window_y)*window_width)+curx; ]; ! ---------------------------------------------------------------------------- Global show_newlines=0; Global show_tabs=0; Global escape_key='\'; ! ---------------------------------------------------------------------------- Constant ASCII_BS=8; Constant ASCII_TAB=9; Constant ASCII_LF=10; Constant ASCII_CR=13; Constant ASCII_DEL=127; Constant ASCII_ESC=27; Constant ARROW_UP=129; Constant ARROW_DOWN=130; Constant ARROW_LEFT=131; Constant ARROW_RIGHT=132; Constant CONTROL_FIRST=0; Constant CONTROL_LAST=31; Constant ASCII_FIRST=32; Constant ASCII_LAST=126; Constant UPPER_FIRST=127; Constant UPPER_LAST=255; [ PrintWidth c x; switch (c) { ASCII_FIRST to ASCII_LAST: return 1; ASCII_LF: return 1; ! Even if we're not showing newlines, so that cursor ! positioning works naturally. ASCII_TAB: if (show_tabs) return 2; else return 8-(x%8); CONTROL_FIRST to CONTROL_LAST: return 2; UPPER_FIRST to UPPER_LAST: return 4; default: CantHappen("Character code not covered in PrintWidth"); } ]; [ Hex n i; i=n/16; if (i<10) print (char) i+'0'; else print (char) i-10+'A'; i=n%16; if (i<10) print (char) i+'0'; else print (char) i-10+'A'; ]; [ PrintChar c x; switch (c) { ASCII_FIRST to ASCII_LAST: print (char) c; ASCII_LF: if (show_newlines) { style reverse; print (char) '/'; style roman; } else print (char) ' '; ASCII_TAB: if (show_tabs) { jump Control_chars; ! handle it as all the other control chars } else spaces 8-(x%8); CONTROL_FIRST to CONTROL_LAST: .Control_chars; style reverse; print (char) 94; ! Carret print (char) c+64; ! Convert control-char to alphabetic counterpart. style roman; UPPER_FIRST to UPPER_LAST: style reverse; print (char) '<', (hex) c, (char) '>'; style roman; default: CantHappen("Character code not covered in PrintChar"); } ]; [ DrawWindowLine startloc y i j x xold; if (startloc==-2) { HLine(LEFT_MARGIN, window_width-LEFT_MARGIN, y+TOP_MARGIN, '.'); return -2; } else if (startloc==-1) { style reverse; HLine(LEFT_MARGIN, window_width-LEFT_MARGIN, y+TOP_MARGIN, '-'); style roman; return -2; } else { GoTo(LEFT_MARGIN, TOP_MARGIN+y); i=startloc; do { j=PeekChar(i); if (j==-1) break; if (x+PrintWidth(j, x)>window_width) break; xold=x; x=x+PrintWidth(j, xold); PrintChar(j, xold); i++; } until (j==ASCII_LF); while (xwindow_width) break; curloc++; } until (j==ASCII_LF); return curloc; ]; [ RetreatOneScreenLine startloc laststart curloc; curloc=RetreatOneLine(startloc); laststart=curloc; while (InRange(curloc, startloc)) { laststart=curloc; curloc=AdvanceOneScreenLine(curloc); } return laststart; ]; [ AdvanceRight loc xdistance x j; do { j=PeekChar(loc); if (j==ASCII_LF or -1) return loc; x=x+PrintWidth(j, x); if (x<=xdistance) loc++; } until (x>=xdistance); return loc; ]; [ DrawBorders; style reverse; HLine(0, scr_xmax, 0, ' '); AtScreen(2, 0, "S: "); print screen_start_address, ", ", screen_start_physical_y; print " P: ", physical_line_start_address, ", ", physical_line_number, ", ", physical_line_start_window_y; print " L: ", logical_line_start_address, ", ", logical_line_start_window_y; print " C: ", cursor_address, ", ", cursor_window_x; HLine(0, scr_xmax, scr_ymax, ' '); AtScreen(2, scr_ymax, "Escape key: "); if (escape_key==27) print "ESC"; else print (char) escape_key; if (show_tabs) print " Show tabs"; if (show_newlines) print " Show newlines"; style roman; ]; [ DrawScreen; DrawBorders(); DrawWindow(); ]; ! ---------------------------------------------------------------------------- Global dialog_origin_x; Global dialog_origin_y; [ PositionCentreDialog width height; dialog_origin_x=(scr_xmax+1-width)/2; dialog_origin_y=(scr_ymax+1-height)/3; ]; [ StartCentreDialog width height y; PositionCentreDialog(width, height); style reverse; for (y=0: y0; StartCentreDialog(42, 10); AtDialog(18, 1, "ZEDIT"); AtDialog(1, 2, "The World's Most Portable Text Editor(?)"); AtDialog(3, 3, "Copyright 1997 Charles Briscoe-Smith"); AtDialog(4, 5, "ZEdit v"); print (string) ZEdit_Version, " ("; for (i=18:i<24:i++) print (char) 0->i; print ") / Inform v"; inversion; if (stdv~=0) { AtDialog(5, 6, "Standard Interpreter version "); print stdv/256, ".", stdv%256; } else { AtDialog(5, 6, "Nonstandard Interpreter!"); } AtDialog(1, 8, "Tell me what you think: "); EndCentreDialog(); GoToCurPos(); redraw_timeout=100; ]; [ DoKey code i; RefreshCache(); while ((logical_line_start_window_y<1 && screen_start_address~=0) || logical_line_start_window_y>=window_height-1) { for (i=0: i maximum_path_length; [ LoadFile; switch (BringInFile(filename)) { 1: DrawScreen(); ShowStatus("Okay."); -1: DrawScreen(); ShowErrorS("Error while loading the file."); -2: DrawScreen(); ShowErrorS("The file was too big!"); } screen_start_address=0; screen_start_physical_y=1; InvalidateIdealX(); RefreshCache(); ]; [ SaveFile; switch (SendOutFile(filename)) { 1: DrawScreen(); ShowStatus("Okay."); 0: DrawScreen(); ShowErrorS("Error while saving the file."); } ]; [ Main; filename->0=12; filename->1='f'; filename->2='i'; filename->3='l'; filename->4='e'; filename->5='n'; filename->6='a'; filename->7='m'; filename->8='e'; filename->9='.'; filename->10='t'; filename->11='x'; filename->12='t'; OpenScreen(); WindowInit(); DrawBorders(); DrawScreen(); IntroBox(); while (DoKey()) ; CloseScreen(); print "^^ Thank you for using this alpha test version of^ ^ ZEDIT^ The World's Most Portable Text Editor(??)^ By Charles Briscoe-Smith^ ^^ Please send your comments to me: ^ ^^"; ]; ! ----------------------------------------------------------------------------