
- •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

READING AND WRITING FILES
Once you have a valid file object, either from the file operator or the currentfile operator, you can read from it or write to it any number of times (or at least until you run out of data to read or until you fill up the file system).
The read operator (and its variants) returns an exit status boolean to let you know whether or not it succeeded. This lends itself nicely to an ifelse statement for error checking, unless you are very sure that the operation will succeed and you want the code to execute as fast as it can (which is, actually, fairly often the case).
Reading from a File
There are several PostScript operators that you can use to read from a file object. All but one require you to provide a buffer into which the operator can place the bytes read from the file. The exception is the read operator; it just reads a single byte from a file, and therefore it doesn’t need a buffer. The size of the buffer is up to you. Most of the read operations in PostScript will simply read until they fill up your buffer. In contrast, the readline operator reads until it sees a specific end-of-line condition. This can create two possible error conditions.
1.You might run out of data to read before you fill your buffer.
2.You might run out of buffer space before you get to an end-of- line condition.
If you run out of data before the buffer is full, the operator you were using to read from the file will tell you (by leaving false on the stack). There is no general way to make sure that your use of readline won’t overflow your buffer. If you’re worried about it, you can certainly use a very large buffer (some implementations limit string sizes to about 64 kilobytes).
Example 14.4 illustrates use of the readstring operator to read data from a file and write it to a new file.
Writing to a File
Writing to a file is very similar to reading from a file, with a couple of exceptions. First of all, the writing operators do not return a boolean
172 |
Chapter 14: USING FILES AND INPUT/OUTPUT TECHNIQUES |

indicating their success or failure. And second, there are a few special character string conventions for such things as newlines and parentheses that apply to strings that you write to a file (detailed in Table 14.4).
Table 14.4: Special Characters
In String Body |
Actual Character |
\n |
newline |
\r |
return character |
\t |
tab |
\b |
backspace |
\f |
form feed |
\\backslash
\( |
left parenthesis |
\) |
right parenthesis |
\XXX |
three-digit octal character code, such as \037 |
\a backslash followed by a newline indicates
no character, and is used to continue a long line
to avoid problems in environments where line lengths are restricted
The most common operator for writing to a file is the writestring operator, which takes an arbitrary string and writes it to the file object you supply. The string is written exactly, byte for byte, to the output file, with the exception of the special backslash escapes. In particular, writestring does not automatically add a newline or carriage return to each line of text written to the file. (If you want a newline, just put \n at the end of your string before you call writestring.)
The program in Example 14.3 writes the StandardEncoding array out to a temporary file.
Example 14.3: Writing an Array Out to a File
/tmpfile (/user/glenn/encoding.ps) (w) file def /scratch 128 string def
tmpfile (/StandardEncoding [ \n) writestring StandardEncoding { %forall
tmpfile ( /) writestring
tmpfile exch scratch cvs writestring tmpfile (\n) writestring
} forall
tmpfile (] def\n) writestring tmpfile closefile
Chapter 14: USING FILES AND INPUT/OUTPUT TECHNIQUES |
173 |

Copying and Renaming Files
In order to copy a file, you need to open it with mode (r), open the destination file with mode (w), and use the loop operator to read from one file and write to the other until you reach the end of the input file. Example 14.4 copies the file (/etc/passwd) to a new file named (/etc/passwd.BAK). It assumes that the original file already exists and can be opened for reading.
Remember to write out the last partial buffer. When the readstring operator returns false, there may be a few bytes in the substring that were read before the end-of-file indication was encountered. This can be seen in the else clause of the conditional in Example 14.4. The contents of the string are written before the files are closed and before the loop is finally exited.
Example 14.4: Copying a File
/infile (/etc/passwd) (r) file def |
% open files and save file objects |
/outfile (/etc/passwd.BAK) (w) file def |
|
/buff 128 string def |
% your buffer for reading operations |
{ % loop |
|
infile buff readstring { %ifelse |
|
outfile exch writestring |
|
}{ %else |
|
outfile exch writestring |
|
infile closefile |
|
outfile closefile |
|
exit % exit the loop |
|
} ifelse |
|
} bind loop |
|
To rename a file, simply use the renamefile PostScript operator if it exists. The program in Example 14.5 checks for the existence of renamefile and if it is not found, it defines a procedure called renamefile that emulates the behavior of the operator by copying the file to the new name and then deleting the original file.
174 |
Chapter 14: USING FILES AND INPUT/OUTPUT TECHNIQUES |