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

Example 14.5: Renaming a File
%emulate “renamefile” if it doesn’t exist (copy the old file to the new and
%then try to delete the old file if possible)...
/renamefile where { pop }{ %ifelse
/renamefile % (oldname) (newname) renamefile - { %def
(w) file /new exch def dup (r) file /old exch def /buff 256 string def
{ % loop
old buff readstring { %ifelse new exch writestring
}{ %else
new exch writestring
old closefile new closefile exit
} ifelse
} loop
/deletefile where { pop deletefile } if } bind def
} ifelse
(/user/glenn/encoding.ps) (/user/glenn/StandardEncoding.ps) renamefile
WRITING FORMATTED DATA TO FILES
If you need to write out a data file or create a file with formatted data in it, you’ll need to become very familiar with the whole family of file writing operators, as well as the data conversion operators (discussed in Chapter 13). Let’s look at some useful techniques.
Writing Out Various Data Types
There are many different PostScript data types. Some of them are easy to write to a file; others present some challenges. To overgeneralize, simple data types (including integer, real, boolean, and mark) are relatively easy to convert into strings and write to a file, whereas composite objects such as dictionaries and arrays require some extra steps.
Let’s look at a few procedures that will help you write out some data types to a file. Example 14.6 and Example 14.7 provide some code that you can draw from. The basic idea is to turn your data into a string, then write that string to the output file with the writestring operator. Example
Chapter 14: USING FILES AND INPUT/OUTPUT TECHNIQUES |
175 |

14.6 shows you how to write numbers and names to a file. You should be careful about white space and newline characters to keep the syntax of the numbers and names correct.
Example 14.6: Writing Numbers and Names to a File
/fd (outputfile.ps) (w) file def /scratch 1024 string def
/Wnum |
% num Wnum - |
{ %def |
|
scratch cvs fd exch writestring } bind def
/Wname % /name Wname - { %def
dup type /nametype ne { %ifelse
fd (% invalid name\n) writestring pop }{ %else
dup xcheck not { fd (/) writestring } if scratch cvs fd exch writestring
}ifelse
}bind def
FontDirectory { %forall pop Wname
fd (\n) writestring
} forall
fd closefile
Notice that the Wnum procedure in Example 14.6 doesn’t pay much attention to the type of its operand, so you could use it for either an integer or a real number. The beauty of the cvs operator (used inside the Wnum procedure to convert the number to a string) is that it is polymorphic; it doesn’t matter what type of object you present to it, as long as there is a reasonable string equivalent. The Wname procedure is very much the same as the Wnum procedure, except that it prints a leading slash if the name presented to it is a literal name. Note that the slash is not part of the name itself. The slash syntax helps you to create a literal name when your program is parsed for the first time, but it just sets the literal flag on the name object, and does not otherwise differ from an executable name.
176 |
Chapter 14: USING FILES AND INPUT/OUTPUT TECHNIQUES |

Spaces, Tabs, Returns, and Special Characters
If you intend to do any serious formatting of the output file, you will need to create white space, and you may need to write out some special characters. For the most part, the backslash syntax used for special characters will do this for you (see Table 14.4). To get them into your output file, just put them into a string body and write that string to the file with the writestring operator. You may find it convenient to use some procedures to do this for you, such as those found in Example 14.7.
Example 14.7: White Space and Special Characters
/fd (outputfile.ps) (w) file def /scratch 1024 string def
% these procedures all depend on “fd” being a valid output file descriptor /Wname % /name Wname -
{ %def
dup type /nametype ne { %ifelse
fd (% invalid name\n) writestring pop }{ %else
dup xcheck not { fd (/) writestring } if scratch cvs fd exch writestring
}ifelse
}bind def
/Wstring { fd exch writestring } bind def /Wline % (string) Wline - { %def
fd exch writestring return } bind def
/space % - space - { %def
fd ( ) writestring } bind def
/return % - return - { %def
fd (\n) writestring } bind def
/tab % - tab - { %def
fd (\t) writestring } bind def
Chapter 14: USING FILES AND INPUT/OUTPUT TECHNIQUES |
177 |