18

In postscript , the cvs *operator* is said to convert a number to a string. How should I use it ? I tried :

100 100 moveto
3.14159 cvs show

or

100 100 moveto
3.14159 cvs string show

but it didn't work.

Any help ?

Pierre
  • 34,472
  • 31
  • 113
  • 192

2 Answers2

16

Try 3.14159 20 string cvs show.

string needs a size and leaves the created string on the stack. cvs needs a value and a string to store the converted value.

If you're doing lots of string conversions, it may be more efficient to create one string and reuse it in each conversion:

/s 20 string def
3.14159 s cvs show
lhf
  • 70,581
  • 9
  • 108
  • 149
  • I don't know if it's a bug in GhostScript (the language specification is unclear on that): It seems strings are not terminated by `cvs`, so if you have a `5 string` and convert first `-10.0` and then `0.0` the string holds `0.0.0` (GPL Ghostscript 9.26). – U. Windl Sep 07 '19 at 22:45
  • See https://stackoverflow.com/questions/57838019/postscript-does-cvs-terminate-the-string – U. Windl Sep 07 '19 at 23:02
13

tldr;

A common idiom is to use a literal string as a template.

 1.42857
(       ) cvs show

more...

You can even do formatted output by presenting cvs with various substrings of a larger string.

%0123456.......
(2/7 =         ) dup 6 7 getinterval
2.85714 exch cvs pop show

But the Ghostscript Style Guide forbids this. And it's pretty much the only published Postscript Style Guide we have. (A discussion about this in comp.lang.postscript.) So a common recommendation is to allocate a fresh string when you need it and let the garbage collector earn its keep.

4.28571 7 string cvs show

Freshly allocating a string can be very important if you're wrapping this action in a procedure.

/toString { (          ) cvs } def
%    vs
/toString { 10 string cvs } def

If you allocate a fresh string, then the enclosing procedure can be treated as a pure function of its inputs. If you use an embedded literal string as the buffer, then this resulting string is state-dependent and will be invalidated if the generating procedure is run again.

too much, don't do this...

As a last resort, the truly lazy hacker will hijack =string, the built-in 128-byte buffer used by = and == to output numbers (using, of course, our friend cvs). This is interpreter-specific and not portable according to the standard.

5.71428 =string cvs show

And if you like that one, you can combine it with ='s other trick: immediately evaluated names.

{ 7.14285 //=string cvs show }   % embed =string in this procedure

This shaves that extra microsecond off, and makes it much harder to interactively inspect the code. Calling == on this procedure will not reveal the fact that you are using =string; it looks just like any other string.

Using =string in this manner inherits all the state-dependency problems described in the last section, ramped up a notch because there's only one =string buffer. And it adds a portability issue to boot, since =string is non standard -- albeit available in historical Adobe implementations and Ghostscript -- it is a legacy hack and should be used only in situations where a legacy hack is appropriate.


something else, no one (here) asked for...

One more trick for the bag, from a post by Helge Blischke in comp.lang.postscript. This is a simple way to get a zero-padded integer.

/bindec         % <integer> bindec <string_of_length_6>
{
        1000000 add 7 string cvs 1 6 getinterval
}bind def 
luser droog
  • 18,988
  • 3
  • 53
  • 105
  • 2 things: 1) WHY is all that necessary? 2) Does a beginner need all those different hacks to make things a microsecond faster? – user242579 Apr 20 '22 at 12:17
  • 1) You're right, it's probably not necessary. 2) No, again you're right, a beginner doesn't need any of these things. I should probably edit the answer and put a *tldr;* header around just the first code snippet. That's all you really need. The rest is just trying to give a deeper understanding and to reference things like the GS style guide and the existence of the comp.lang.postscript newsgroup. – luser droog Apr 20 '22 at 16:36
  • @user242579 edited the answer. Thank you for the comment! – luser droog Apr 20 '22 at 16:45
  • Just to point out that the extra depth here is really useful sometimes - I was looking for right justifying a string with spaces and got the right idea here... – Klapaucius Klapaucius Feb 24 '23 at 01:02