Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Reid G.C.Thinking in PostScript.1990.pdf
Скачиваний:
17
Добавлен:
23.08.2013
Размер:
846.44 Кб
Скачать

Example 11.6: Anatomy of the putinterval Operator

data_structure position_key data_structure putinterval 12 array 5 [ /f /g /h /i /j /k ] putinterval

(abcDEF) 0 (ABC) putinterval

TIP

If you have difficulty remembering the order of operands to the put and

 

get operators, remember that they work in the same order that def and load

 

take their operands: the key comes before the value.

 

 

 

 

CONCATENATING ARRAYS AND STRINGS

Arrays and strings have a fixed length. You cannot dynamically extend them. In order to tack two of them together, you must allocate a third array or string that is big enough to hold the other two, then copy them both into it. There is no easier way to do it, unfortunately.

Example 11.7 sets forth a procedure called concatenate. This concatenate procedure tacks together two string bodies into a third string that is left on the operand stack as the result of the procedure call. The procedure works with arrays in precisely the same way. If you copy this example, be careful not to call it concat, since that is the name of another PostScript operator for concatenating matrices.

The roll operator is used in the body of this procedure to avoid having to make any dictionary entries. This is intentional, since a procedure used as an operator-equivalent (as concatenate is) should have as few side effects as possible.

Note the use of putinterval in this procedure. It is called once to copy the body of the first argument into the destination at position 0, then it is called a second time with the position in the destination equal to the length of the first argument, so the second argument lands exactly where the first part left off. Note the use of length to determine this position, and the careful use of dup and index to keep copies of the various strings or arrays until we are done with them. The length, putinterval, and type operators all consume their operands, so you must take care to operate on a copy of the original arguments until they are no longer needed.

Chapter 11: CREATING AND MANIPULATING DATA

139

Example 11.7: Concatenating Two Strings Together

/concatenate

% (string1) (string2) concatenate string3

 

% array1 array2 concatenate array3

{ %def

 

dup type 2 index type 2 copy ne { %if pop pop

errordict begin (concatenate) typecheck end }{ %else

/stringtype ne exch /arraytype ne and {

errordict begin (concatenate) typecheck end

} if

} ifelse

dup length 2 index length add 1 index type /arraytype eq { array }{ string } ifelse

%stack: arg1 arg2 new dup 0 4 index putinterval

%stack: arg1 arg2 new

dup 4 -1 roll length 4 -1 roll putinterval

%stack: new

}bind def

(string1) (string2) concatenate ==

[ /zero /one /two ] [ /three /four /five /six ] concatenate ==

INPUT AND OUTPUT OF STRING DATA

A string is basically a chunk of memory in which characters are stored. The string body is created first, then characters may be added to it with the copy, put, putinterval, read, readstring, or readhexstring operators.

There are two primary sources for string data. The most commonly used one is to supply the data as a literal string (using the familiar parentheses), as shown in Example 11.8.

Example 11.8: Creating a Literal String

%normal “show” string: (This is a string) show

%exactly the same result using a hex string: <54686973206973206120737472696e67> show

140

Chapter 11: CREATING AND MANIPULATING DATA

The scanner allocates a string body of the appropriate size and copies the bytes into it for you, leaving a string object on the top of the operand stack. The string is delimited by parentheses, and can contain parentheses if they are quoted with a backslash character before the parens, like this:

(some \) parens in a \( string body).

The other main source of string data, other than synthetically created strings, is a file object. You can open a file and read bytes directly into string bodies, but the strings must have been allocated beforehand. Example 11.9 shows this quite well.

Example 11.9: Reading String Data from a File

/buffer 128 string def

currentfile buffer readline % reads directly from input This is a string

show

% read through /etc/password and print line containing “Glenn” /buffer 128 string def

/passwd (/etc/passwd) (r) file def { %loop

passwd buffer readline { dup (Glenn) search {

pop pop pop print(\n) print flush exit

}{ pop } ifelse }{ exit } ifelse

} loop

passwd closefile

ARRAYS VERSUS DICTIONARIES

There are several differences between arrays and dictionaries that make them more (or less) appropriate for a given task. The most important differences are:

Arrays can be accessed sequentially, but dictionaries cannot be accessed sequentially (the forall operator uses hash table order).

Chapter 11: CREATING AND MANIPULATING DATA

141

Dictionary access can be made automatic using name lookup. By contrast, the only way to retrieve something from an array is with get or getinterval.

Arrays need about half the memory that dictionaries require, since there is no key to be stored.

Arrays can be created dynamically, without having to know ahead of time how many entries may be needed.

It is unfortunately very common for programs to allocate huge dictionaries but never to use all the space that was allocated. This is often a result of the debugging cycle, when a dictionary was made large in response to a dictfull error or in anticipation of larger program growth. This is easily enough avoided, of course, but it is common enough that it is worth mention.

As a rule of thumb, if the data you need to store are needed sequentially or all of the entries are needed at once, you are better off using arrays than dictionaries. Dictionaries are most powerful for storing procedures and variables for your program, and have only specialized applications for the data that is used by a program.

ADVANCED TECHNIQUES

PostScript programs that read data directly from a file sometimes have to perform extensive string manipulation to use the data. An interesting trick for parsing data is to use the token operator. If your data are ASCII and can be interpreted somehow as PostScript-like objects, your parsing task can be greatly simplified.

Consider the program in Example 11.10 that reads pairs of points from the input file and constructs line segments from them. The output of this example is shown in Figure 11.1.

Example 11.10: Reading and Executing Data from a File

%!PS-Adobe-2.0 EPSF-2.0 %%BoundingBox: 0 0 150 150 %%EndComments

100 300 translate

142

Chapter 11: CREATING AND MANIPULATING DATA