- •Preface
- •DESIGN FEATURES
- •STRUCTURED PROGRAMMING TECHNIQUES
- •PROGRAMMING TASKS
- •WINDOW SYSTEMS, COMMUNICATIONS, AND DISPLAYS
- •DATA STRUCTURES AND ALGORITHMS
- •CONCLUDING THOUGHTS
- •PostScript is Not Like C
- •COMPARISON OF LANGUAGE MECHANISMS
- •EXPRESSING AN ALGORITHM AS A PROGRAM
- •THE UNIX SHELL AND OPERATING SYSTEM
- •INPUT, OUTPUT, AND THROUGHPUT
- •CONCLUDING THOUGHTS
- •Foundations
- •POSTSCRIPT LANGUAGE SYNTAX
- •SIMPLE PROGRAM STRUCTURE
- •Make Definitions First
- •Indentation Style
- •SETTING UP TEMPLATES
- •DECLARING AND USING VARIABLES
- •Arithmetic with Numeric Variables
- •Using the // Notation for Constants
- •ALLOCATING MEMORY
- •GETTING MEMORY BACK
- •OPENING AND CLOSING FILES
- •COMPARISONS AND EQUALITY OF OBJECTS
- •CONCLUDING THOUGHTS
- •Some Typical Programs
- •A TYPICAL PAGE DESCRIPTION PROGRAM
- •FONT PROGRAMS
- •PROGRAMS THAT READ DATA
- •QUERY PROGRAMS
- •ENCAPSULATED POSTSCRIPT PROGRAMS
- •PERSISTENTLY RESIDENT PROGRAMS
- •CONCLUDING THOUGHTS
- •Understanding the Stack
- •A QUICK OVERVIEW OF DATA TYPES
- •NAME LOOKUP
- •HOW OPERATORS USE THE STACK
- •GROUPING AND VISUAL CHUNKING
- •THINKING BACKWARD AND SIDEWAYS
- •COMPOSITE OBJECTS
- •THE OTHER STACKS
- •The Dictionary Stack
- •The Execution Stack
- •The Graphics State Stack
- •CONCLUDING THOUGHTS
- •Trusting the Stack
- •SAFETY OF DATA ON THE STACK
- •WHERE ARE THE DATA GOING?
- •REARRANGING THE STACK
- •Using the dup and index Operators
- •Using the roll Operator
- •CONDITIONALS AND LOOPS
- •RECURSION AND LOCAL VARIABLES
- •CONCLUDING THOUGHTS
- •Building Conditional Statements
- •SIMPLE CONDITIONALS
- •SETTING UP THE CONDITION
- •CONDITIONALS ARE NOT MAGIC
- •NESTED CONDITIONALS AND ELSE CLAUSES
- •COMPOUND CONDITIONALS
- •CONCLUDING THOUGHTS
- •Using Looping Constructs
- •LOOP BASICS
- •USING THE LOOP INDEX
- •LOOPS ARE PROCEDURE BODIES
- •LOOPS OF INSTRUCTIONS
- •EXITING LOOPS PREMATURELY
- •CONCLUDING THOUGHTS
- •Procedures
- •WHAT EXACTLY IS A PROCEDURE?
- •PARAMETER PASSING
- •CONSTRUCTING GOOD PROCEDURES
- •What to Name Your Procedure
- •A Useful Naming Convention
- •SELF-MODIFYING PROCEDURES
- •CONCLUDING THOUGHTS
- •Using Dictionaries
- •DICTIONARIES FOR NAME SCOPING
- •LOCAL DICTIONARIES
- •GLOBAL DICTIONARIES OF PROCEDURES
- •MAINTAINING THE DICTIONARY STACK
- •INTO AND OUT OF DICTIONARIES
- •LOOKING INTO DICTIONARIES
- •Using the forall Operator
- •Using the where and known Operators
- •REDEFINING OPERATORS
- •Changing the Behavior of Operators
- •Debugging with Redefined Names
- •Proper Nesting of Redefinitions
- •CONCLUDING THOUGHTS
- •Creating and Manipulating Data
- •CONSTRUCTING AN ARRAY
- •CONSTRUCTING A STRING
- •MANIPULATING DATA WITH PUT AND GET
- •CONCATENATING ARRAYS AND STRINGS
- •INPUT AND OUTPUT OF STRING DATA
- •ARRAYS VERSUS DICTIONARIES
- •ADVANCED TECHNIQUES
- •CONCLUDING THOUGHTS
- •Storing and Using Data
- •Data and the Operand Stack
- •Data and Algorithms for Underlining
- •CLASSICAL DATA STRUCTURES
- •Linked Lists
- •Using Arrays to Form Lists
- •Using Dictionaries to Form Lists
- •Queues, Trees, and Other Data Structures
- •CONCLUDING THOUGHTS
- •Program Data and Instructions
- •TURNING DATA INTO INSTRUCTIONS
- •TURNING INSTRUCTIONS INTO DATA
- •DATA CONVERSIONS
- •CONCLUDING THOUGHTS
- •File Objects
- •Streams and Files
- •PostScript File Operators
- •OPENING AND CLOSING FILES
- •READING AND WRITING FILES
- •Reading from a File
- •Writing to a File
- •Copying and Renaming Files
- •WRITING FORMATTED DATA TO FILES
- •Writing Out Various Data Types
- •Spaces, Tabs, Returns, and Special Characters
- •FILE STATUS INFORMATION
- •RANDOM VERSUS SEQUENTIAL ACCESS
- •CONCLUDING THOUGHTS
- •Appendix
- •Answers to Exercises
%the following three lines of code will reproduce the
%first two lines of this program in the output file: (%!) Wline
/fd Wname space ((outputfile.ps) (w) ) Wstring /file cvx Wname space /def cvx Wname return
fd closefile
FILE STATUS INFORMATION
One of the most useful bits of information about a file is the number of bytes it contains. On most PostScript interpreters with file systems (including printers with a hard disk), there are two ways to determine this. The first is the status operator, to which you pass a file name. The status operator actually provides several kinds of information about the file, including how many pages of disk space it occupies (a page is typically 1,024 bytes), when it was last accessed, when it was written, and how many bytes it contains. Here is the syntax of the status operator.
filename_string status
pages bytes referenced created true
or
false
The status operator returns a boolean which is false if the file exists, true otherwise. If the file exists, the status operator also returns the other fields shown in the syntax of the status operator. Example 14.8 shows the status operator in use.
Example 14.8: Using status to Check a File
% this code opens a file for reading if it exists, else error message (/etc/passwd) dup status { %ifelse
4 { pop } repeat % get rid of interesting file data
(r) open }{ %else
print ( is not a valid file name. Cannot open.\n) print flush stop
} ifelse
178 |
Chapter 14: USING FILES AND INPUT/OUTPUT TECHNIQUES |
NOTE: The status operator and the bytesavailable operator may not be present in all implementations of the PostScript language. It is wise to check for its existence before using it.
If the file is already open and you have a file object that represents it, you can use the bytesavailable operator to determine how many bytes remain in the file object. If you have already read some of the bytes, bytesavailable will always return the remainder, or 0 if there are no more bytes to be read.
Here is the syntax of the bytesavailable operator:
file_object bytesavailable int |
how many bytes left in file |
The program in Example 14.9 uses the bytesavailable operator to pick a random number for file access.
NOTE: The bytesavailable and setfileposition operators may not be present in all implementations of the PostScript language. It is wise to check for its existence before using it.
Example 14.9: Random File Access with setfileposition
% get a random word from UNIX dictionary file:
/fd (/usr/dict/words) (r) file def |
% open the file |
rand fd bytesavailable mod |
% random number within file size |
fd exch setfileposition |
% seek to that position in the file |
fd 128 string readline pop pop |
% read partial line (at random position) |
fd 128 string readline pop |
% read entire line --> your word |
100 600 moveto |
|
/Times-Italic 24 selectfont show |
|
RANDOM VERSUS SEQUENTIAL ACCESS
Under normal circumstances, you should treat a file as though it were only readable sequentially. That way, your program will not break if it is transported into another environment where files may be implemented differently. If you really need to perform random access on a file object, the setfileposition operator will help you. You need to open the file either for read (r) or write (w) to use the setfileposition operator (see Example 14.9).
Chapter 14: USING FILES AND INPUT/OUTPUT TECHNIQUES |
179 |
If you try to set the file pointer beyond the end of the file with setfileposition, you will get an ioerror, so be careful that you know how big the file is (using either the status or the bytesavailable operator).
CONCLUDING THOUGHTS
This chapter presented a broad overview of file operations in PostScript and how to use them effectively. PostScript supports file I/O operations in much the same way that other languages do, assuming that you have an interpreter with full support for a file system. Remember, these and other language extensions must be used somewhat carefully to make your code truly portable across all implementations of the PostScript interpreter.
You should now have a pretty solid understanding of the PostScript language and how it relates to other languages that you already know. Hopefully by now you have even started to enjoy the fact that PostScript works backwards and upside down, and you have learned to appreciate its strengths and unique language characteristics—in short, you have learned how to think in PostScript.
The simplicity and power of PostScript makes it a very good language to write programs quickly and confidently that work the very first time, like many of the examples in this book. By now you will have developed a strong programming style and technique that lets you rough out a program, look up the syntax of an occasional PostScript operator, and proceed quickly with the knowledge that you are doing the right thing—and in one of the world’s most interesting programming languages.
EXERCISES
1.Write a procedure that finds all the fonts on the local hard disk specified as (fonts/FontName) and write just the font names to the standard output file. (HINT: use the filenameforall operator.)
2.Adapt the program from Exercise 1 to write both the font names and the byte sizes of the font files to the standard output file.
3.Write a program that will open a file called prog.ps and execute the file one token at a time (using the token and exec operators), writing
180 |
Chapter 14: USING FILES AND INPUT/OUTPUT TECHNIQUES |
each token to another file called trace.ps. This program might be useful for debugging prog.ps, since you can determine exactly how much of the file prog.ps has been executed by looking in the trace file. Don’t worry about getting the tokens to look exactly right in the output file, as long as something gets written for each one and the program executes to completion without error. (HINT: You will need to be very careful with procedure bodies.)
4.In Exercise 2, you may have noticed that a lot of PostScript language tokens do not have readable representations once they have been tokenized by the interpreter. Expand on Exercise 2, making sure that strings, procedure bodies, and literal names are represented correctly in the output file. You should be able to actually execute the resulting trace.ps file and get the same results as the original file.
Chapter 14: USING FILES AND INPUT/OUTPUT TECHNIQUES |
181 |
182 |
Chapter 14: USING FILES AND INPUT/OUTPUT TECHNIQUES |
Appendix
Appendix
APPENDIX |
183 |
184 |
APPENDIX |