Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

yet another prototype document formatting engine

37 views
Skip to first unread message

luser- -droog

unread,
Apr 25, 2011, 2:09:39 AM4/25/11
to
This implements a very bare-bones text-with-embedded-
control-codes processor. I'm hoping the 'clippath pathbbox'
will eliminate all that letter/a4 gibberish.

Comments welcome.

504(0)12:54 AM:ps 0> cat ibis.ps
%!
/show { dup print show } bind def
/inch {72 mul} def

/pagesize [ clippath pathbbox ] def

%/letter {/pagesize [8.5 inch 11 inch] def} def

/setbounds {
/Y exch def
/X exch def
/y exch def
/x exch def
} def

/savebounds {
/bnds [ x y X Y ] def
} def

/resetbounds {
bnds aload pop setbounds
} def

% n margin -
% set margin to n points from edges
/margin {
clippath pathbbox
4 index sub 4 1 roll
4 index sub 4 1 roll
4 index add 4 1 roll
4 index add 4 1 roll
setbounds savebounds
pop
} def

/eol {
(\n) print
x
Y lead sub
dup /Y exch def
moveto
Y y lt { showpage startpage } if
} def

/blank {
eol
} def

/startpage {
resetbounds
eol
} def

% str part -
% show the string
/part {
show
} def

% show a space
/space {
( ) part
} def

/escape (\\) def
% str scan -
% scan a string for the escape sequence
% execute pre part
% pull token from
%
/scan {
dup length 0 eq {
pop blank
}{
escape search {
part
space
pop
token {
exec scan
} if
}{
part eol
} ifelse
} ifelse
} def

/buf 500 string def
% file|string ibis -
% process a source file (by name if string)
/ibis {
dup type /stringtype eq { (r) file } if
dup type /filetype ne { /ibis cvx /typecheck cvx .error } if
/src exch def

{
src buf readline exch
scan
not { exit } if
} loop
} def

/r { /Palatino-Roman 15 selectfont
lead 20 lt { /lead 20 def } if
} def
/i { /Palatino-Italic 15 selectfont
lead 20 lt { /lead 20 def } if
} def

%letter
1 inch margin savebounds
/lead 0 def
r
startpage

currentfile ibis
Lorem ipsum dolor sit amet, consectataur adipisicing
elit, sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim\i ad minim\r veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis
aute irure dolor in reprehenderit in voluptate velit esse cillum
dolore eu fugiat nulla pariatur.
\exit
pop pop

/escape <abcdef00> def
% To run this program upon itself, we must redefine the
% escape string in such a manner that the semantic
% content does not match the syntactic structure
% (so it doesn't choke upon reading this very
% definition), ie. an encoded form.
% Otherwise, it would attempt to execute the name '\',
% and probably won't find such a thing defined.
(ibis.ps)(r)file ibis

luser- -droog

unread,
Apr 25, 2011, 12:00:44 PM4/25/11
to
Version 2 changes the escape code to @.
The \i italics command now requires a delimited argument.
eg. \i{this is italics}
And you can used any pair of braces for the delimiters
and they can span multiple lines!

508(1)10:46 AM:ps 1> cat ibis.ps
%!

/show { dup print show } bind def

/inch {72 mul} def

% get dimensions from the environment


/pagesize [ clippath pathbbox ] def
%/letter {/pagesize [8.5 inch 11 inch] def} def


% call margin to set text bounds
% textsetting will decrement Y after each line
% startpage calls resetbounds to restore Y

/setbounds {
/Y exch def
/X exch def
/y exch def
/x exch def
} def

/savebounds {
/bnds [ x y X Y ] def
} def

/resetbounds {
bnds aload pop setbounds
} def

% n margin -
% set margin to n points from edges
/margin {
clippath pathbbox
4 index sub 4 1 roll
4 index sub 4 1 roll
4 index add 4 1 roll
4 index add 4 1 roll
setbounds savebounds
pop
} def


/startpage {
resetbounds
eol
} def


% decrement Y
% moveto(x,Y)
% newpage if off the bottom


/eol {
(\n) print
x
Y lead sub
dup /Y exch def
moveto
Y y lt { showpage startpage } if
} def

% called for a blank line
/blank {
eol
} def

% str part -
% show the string
/part {
show
} def

% show a space
/space {
( ) part
} def


% Scribe-esque 'fontchanges'

% (abcd) pull (bcd) (a)
% snag the first character from the string
/pull {
dup 0 1 getinterval exch %get exch
1 1 index length 1 sub getinterval exch
} def

% delimiter pairs
/pairs mark
([) (])
(<) (>)
(\() (\))
({) (})
(`) (')
(:) (;)
%counttomark copy
%counttomark 2 idiv -2 2 {
% 2 roll exch
%} for exch
counttomark 2 idiv dup dict begin { def } repeat
pop
currentdict end
def

/nestmax 20 def
/nest nestmax array def
/nestcur -1 def

% ? nestadd -
/nestpush {
/nestcur nestcur 1 add def
nestcur nestmax eq { ERROR_nestpush } if
nest nestcur 3 -1 roll put
} def

/nestpop {
nestcur 0 ge {
nest nestcur get 0 get exec
/nestcur nestcur 1 sub def
} if
} def

% {undo} ([text]rem) delim (rem)
% show text and return control
/delim {
pull
pairs exch 2 copy known {
get
}{
exch pop %not a pair, delimiter matches itself
} ifelse
dup 3 1 roll
% pstack()=
search {
4 -1 roll pop
part pop
exch exec
}{
% no delimiter before EOL!
%exch
3 1 roll
[ 3 1 roll ]
nestpush
} ifelse
} def

/atsign (@) def
% str scan -
% scan a string for last nested open delimiter
% call undo proc if found
% then, scan string for the escape sequence
% execute pre part
% pull token from post
% execute token
% leave remainder on stack


/scan {
dup length 0 eq {
pop blank
}{

nestcur 0 ge {
nest nestcur get 1 get
% pstack()=
search {
part pop
nestpop
} if
} if
% pstack()=
atsign search {
part %space


pop
token {
exec scan
} if
}{
part eol
} ifelse
} ifelse
} def

/buf 500 string def
% file|string ibis -
% process a source file (by name if string)
/ibis {
dup type /stringtype eq { (r) file } if

dup type /filetype ne { ERROR_ibis } if
/src exch def

{
src buf readline exch
scan
not {

Y bnds 3 get lt { showpage startpage } if
exit
} if
} loop
} def

/fs 15 def

/fonts <<
/rom /Palatino-Roman findfont fs scalefont
/ita /Palatino-Italic findfont fs scalefont
>> def

% stash currentfont in an undo proc
% lookup and set FONT
% call delim to search
/fonttemplate {
FONT
[ currentfont /setfont cvx ] cvx 3 1 roll
fonts exch get setfont
delim
} def

% FONT createfont proc
% generate a font setting proc
/createfont {
/fonttemplate load dup length array copy
dup 0 4 -1 roll put
cvx
} def

/i /ita createfont def
/r /rom createfont def

%letter
1 inch margin
/lead 20 def
fonts /rom get setfont
startpage

currentfile ibis
Lorem ipsum dolor sit amet, consectataur adipisicing

elit, sed do eiusmod tempor @i[incididunt ut labore] et dolore magna
aliqua. Ut enim @i(ad minim) veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip @i |ex ea commodo| consequat. Duis
aute irure dolor in reprehenderit in voluptate velit @i<esse cillum


dolore eu fugiat nulla pariatur>.
\exit pop pop

/escape <abcdef00> def
% To run this program upon itself, we must redefine

% the escape string in such a manner that the semantic content does
% not match the syntactic structure (so it doesn't choke upon
% reading this very definition), ie. an encoded form.


% Otherwise, it would attempt to execute the

% name '\', and probably won't find such a thing defined.
%(ibis.ps)(r)file ibis

509(1)10:46 AM:ps 0>

luser- -droog

unread,
Apr 27, 2011, 12:59:34 AM4/27/11
to
Version 3 adds a rudimentary user manual, and bold and typewriter
fonts.
I'm stilling working on how to do the enter/leave constructs.
I think I need some fancy dictstack manipulations. Enter can
begin a dict implementing the required specialized names and register
its position on the dictstack in another dictionary, keyed by the
the name of the construct. Then leave can lookup the position by
name, compute the difference between the current dictstack depth
and the position to be removed then, just:
dup { currentdict end } repeat
end
{ begin } repeat
I think this should work.


512(1)11:49 PM:ps 0> cat ibis.ps
%!
%%Documentation: (atend) :)

/show { dup print show } bind def

/inch {72 mul} def

% mark k0 v0 .. kN vN dicttomark dict
/dicttomark {


counttomark 2 idiv dup dict begin { def } repeat
pop currentdict end
} def

% get dimensions from the environment


/pagesize [ clippath pathbbox ] def
%/letter {/pagesize [8.5 inch 11 inch] def} def


% call margin to set text bounds
% textsetting will decrement Y after each line
% startpage calls resetbounds to restore Y

% LLx LLy URx URy setbounds -


/setbounds {
/Y exch def
/X exch def
/y exch def
/x exch def
} def

/savebounds {
/bnds [ x y X Y ] def
} def

/resetbounds {
bnds aload pop setbounds
} def

% n margin -
% set margin to n points from edges
/margin {
clippath pathbbox
4 index sub 4 1 roll
4 index sub 4 1 roll
4 index add 4 1 roll
4 index add 4 1 roll
setbounds savebounds
pop
} def


% reset page parameters,
% position cursor
/startpage {
resetbounds
eol
} def

/nextpage {
showpage startpage
} def


% Y -= lead


% moveto(x,Y)
% newpage if off the bottom
/eol {
(\n) print
x
Y lead sub
dup /Y exch def
moveto

Y y lt //nextpage if
} def

% start new paragraph
/blank {
%eol
} def

% str part -
% show part of line
/part {
show
} def

% show a space
/space {
( ) part
} def


% Scribe-esque 'fontchanges'

% (abcd) pull (bcd) (a)
% snag the first character from the string
/pull {
dup 0 1 getinterval exch

1 1 index length 1 sub getinterval exch
} def

% delimiter pairs
/pairs mark
([) (])
(<) (>)
(\() (\))
({) (})
(`) (')
(:) (;)

%counttomark copy %accept inverted pairs
%counttomark 2 idiv -2 2 { % no. bad idea.


% 2 roll exch
%} for exch

dicttomark def

% the nested delimiter stack
% an element consists of a 2-element array
% [ proc string ]
% when the string is found, the proc gets executed
% and the record gets popped


/nestmax 20 def
/nest nestmax array def
/nestcur -1 def

% ? nestpush -


/nestpush {
/nestcur nestcur 1 add def

nestcur nestmax eq { NEST_TOO_DEEP_in_nestpush } if


nest nestcur 3 -1 roll put
} def

/nestpop {
nestcur 0 ge {
nest nestcur get 0 get exec
/nestcur nestcur 1 sub def
} if
} def

% {undo} ([text]rem) delim (rem)
% show text and return control
/delim {
pull
pairs exch 2 copy known {
get
}{
exch pop %not a pair, delimiter matches itself
} ifelse

dup 3 1 roll %stash a copy of the termination string
% pstack()=
search {
4 -1 roll pop % discard stashed string
%part
scan


pop
exch exec
}{ % no delimiter before EOL!

3 1 roll % retrieve stashed string
[ 3 1 roll ] % create [ undo (term) ] record
nestpush
} ifelse
} def

part %eol
} ifelse
} ifelse
} def

/buf 500 string def
% file|string ibis -
% process a source file (by name if string)
/ibis {
dup type /stringtype eq { (r) file } if

dup type /filetype ne { NOT_A_FILE_in_ibis } if
/src exch def

{
src buf readline exch
scan

eol


not {
Y bnds 3 get lt { showpage startpage } if
exit
} if
} loop
} def

/fs 15 def

/fontset mark
/b /Palatino-Bold findfont fs scalefont
/r /Palatino-Roman findfont fs scalefont
/i /Palatino-Italic findfont fs scalefont
/t /Courier findfont fs scalefont
dicttomark def

/createundofont {
[ currentfont /setfont cvx ] cvx
} def

% ((s)tr) fn change (tr)
/change {
createundofont
3 1 roll
fontset exch get setfont
delim
} def

/b { /b change } def
/i { /i change } def
/r { /r change } def
/t { /t change } def
/@ { (@) part } def

/enter { } def
/leave { } def

/abort {showpage currentfile flushfile clear exit} def

/default {


1 inch margin
/lead 20 def

fontset /r get setfont
} def


%Manual

default startpage
currentfile cvlit ibis

@b[This is the formatting sample and input playpen:]

@t `Lorem ipsum dolor sit amet,' consectataur adipisicing


elit, sed do eiusmod tempor @i[incididunt ut labore] et dolore magna
aliqua. Ut enim @i(ad minim) veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip @i |ex ea commodo| consequat. Duis
aute irure dolor in reprehenderit in voluptate velit @i<esse cillum
dolore eu fugiat nulla pariatur>.

@nextpage

@b[Ibis User Manual]

Introduction
Ibis is a document production program. It is being designed
to mimic the behavior described in the July 1978 CMU
Scribe Introductory Manual that I found through wikipedia.

Ibis is written in postscript and therefore assumes that
it is running in a postscript environment with graphics
devices handled appropriately. It renders text using
postscript graphics primitives. Thus, none of the extensive
device handling performed by Scribe is necessary here.

Paragraphs are separated by blank lines and commands,
if present, are flagged with an "@@ " sign. If you want
an "@@ " sign to appear in your output, you must type two
of them: "@@ @@ ".

The above, from the Scribe Manual, presents some difficulty
for emulation from the start. Ibis processes text line-by-line
using the readline operator. Then it searches throught the line
for the "@@ " sign and prints the preceding string. Ibis borrows
the postscript scanner to recognize and construct name objects
for commands. This provides an obvious and very nifty shortcut:
the sequence @@ {procedure} inserted in running text will
attempt to execute the postscript array {procedure} before
proceeding with the text. So if I can handle the constructs
properly, you can access postscript execution anywhere at
any time.

The difficulty is that any command we use after the @@ sign
must be followed by something that will delimit that name
for the postscript scanner. In particular, the @@ sign itself
when used as a command to print the @@ sign on the output
page must always be followed by a space (which will be consumed).

This same difficulty also rears its head if you use creative
delimiters for the font-change commands. Any delimiter that
has a rightward partner ('(', '{', '[', '<', '`', ':') will
expect to be terminated by that right-hand-side character
(')', '}', ']', '>', ''', ';'). But you may also use any other
character and the same character will be considered the
termination as soon as it's encountered. Eg. "@@ i/italics/"
produces "@i/italics/", but "@@ t `typewriter', since the
backquote is not a postscript delimiter, requires an extra
space to produce "@t `typewriter'" or it'll choke, attempting
to execute t`typewriter'"whatever-else_may:be:there:before:a-delimiter
as a postscript name.

One interesting sidenote (of questionable utility) is if you
use the < angle brackets > as delimiters, vim will flag any
non-hexidecimal characters as postsript syntax errors.
This makes it look catchy in the source-code.

Ibis currently implements a small number of font-change codes:
@t(@@ i[phrase]) @i[Italics]
@t(@@ b[phrase]) @b[Boldface]
@t(@@ r[phrase]) @r[Roman (the normal typeface)]
@t(@@ t[phrase]) @t[Typewriter font]

@abort
This is the old way to exit ibis
and go back to the postscript scanner:
\exit
pop pop


513(1)11:49 PM:ps 0>

luser- -droog

unread,
Apr 28, 2011, 4:28:00 AM4/28/11
to
On Apr 26, 11:59 pm, luser- -droog <mijo...@yahoo.com> wrote:
> Version 3 adds a rudimentary user manual, and bold and typewriter
> fonts.
> I'm stilling working on how to do the enter/leave constructs.
> I think I need some fancy dictstack manipulations. Enter can
> begin a dict implementing the required specialized names and register
> its position on the dictstack in another dictionary, keyed by the
> the name of the construct. Then leave can lookup the position by
> name, compute the difference between the current dictstack depth
> and the position to be removed then, just:
>   dup { currentdict end } repeat
>   end
>   { begin } repeat
> I think this should work.
>

Of course that doesn't work. It should be:
mark exch { currentdict end } repeat
end
counttomark { begin } repeat pop

I've got enter(quotation) and leave(quotation) working, I think.
And I did a bit of juggling with the newlines, until the output
looked right.

This version prints a little sample, a brief user manual, and then
the source code itself in big, readable 11-pt Courier.


503(0)03:22 AM:ps 0> cat ibis.ps
%!
%%Documentation: (atend) :)

/show { dup print show } bind def

/inch {72 mul} def

% mark k0 v0 .. kN vN dicttomark dict
/dicttomark {
counttomark 2 idiv dup dict begin { def } repeat
pop currentdict end
} def

% get dimensions from the environment
/pagesize [ clippath pathbbox ] def
%/letter {/pagesize [8.5 inch 11 inch] def} def


% call margin to set text bounds
% textsetting will decrement Y after each line
% startpage calls resetbounds to restore Y

% LLx LLy URx URy setbounds -
/setbounds {
/Y exch def
/X exch def
/y exch def
/x exch def
} def

/savebounds {
/bnds [ x y X Y ] store
} def

/nextpage {
showpage startpage
} def

dup /Y exch store


moveto
Y y lt //nextpage if
} def

% "hard" eol
% called by ibis after scan returns
/heol {
textonline { eol } if
} def

% "blank" line


% start new paragraph
/blank {

eol
} def

% str part -
% show part of line
/part {

dup length 0 gt {
/textonline true store
} if
show
} def


% Scribe-esque 'fontchanges'

/nestcur nestcur 1 add store


nestcur nestmax eq { NEST_TOO_DEEP_in_nestpush } if
nest nestcur 3 -1 roll put
} def

/nestpop {
nestcur 0 ge {
nest nestcur get 0 get exec

/nestcur nestcur 1 sub store
} if
} def

/getrighthandside {


pairs exch 2 copy known {
get
}{
exch pop %not a pair, delimiter matches itself
} ifelse

} def

% {undo} ([text]rem) delim (rem)

% pull first char from string
% recurse to scan for text
% execute undo if closing delimiter is found in string
% otherwise push undo record on the neststack,
% the topmost record will be checked first on subsequent scans
/delim {
pull
getrighthandside


dup 3 1 roll %stash a copy of the termination string
% pstack()=
search {
4 -1 roll pop % discard stashed string
%part
scan
pop
exch exec
}{ % no delimiter before EOL!
3 1 roll % retrieve stashed string
[ 3 1 roll ] % create [ undo (term) ] record
nestpush
} ifelse
} def

% {post} {body} ([text]rem) delim (rem)
% pull first char from string
% execute {body} on (text)
% execute {post} on (rem)
/delbody {
pull
getrighthandside
search { % p b post match pre
4 -1 roll exec % p p m
pop
exch exec
}{
NO_DELIM_IN_LINE_in_delbody
} ifelse
} def

/atsign (@) def
% str scan -
% scan a string for last nested open delimiter
% call undo proc if found
% then, scan string for the escape sequence
% execute pre part
% pull token from post
% execute token
% leave remainder on stack
/scan {

% dup length 0 eq {
% pop blank
% }{

nestcur 0 ge {
nest nestcur get 1 get
% pstack()=
search {

%part
scan


pop
nestpop
} if
} if
% pstack()=
atsign search {
part %space
pop
token {
exec scan
} if
}{
part %eol
} ifelse

% } ifelse
} def

/buf 500 string def
/src null def
/textonline false def


% file|string ibis -
% process a source file (by name if string)
/ibis {
dup type /stringtype eq { (r) file } if
dup type /filetype ne { NOT_A_FILE_in_ibis } if

/src exch store

{
src buf readline exch
/textonline false store


dup length 0 eq { pop blank }{

scan
heol
} ifelse


not {
Y bnds 3 get lt { showpage startpage } if
exit
} if
} loop
} def

/fs 11 def

/default {
1 inch margin
/lead 12 def


fontset /r get setfont
} def

/fontset mark


/b /Palatino-Bold findfont fs scalefont
/r /Palatino-Roman findfont fs scalefont
/i /Palatino-Italic findfont fs scalefont
/t /Courier findfont fs scalefont
dicttomark def

/createundofont {
[ currentfont /setfont cvx ] cvx
} def

% ((s)tr) fn change (tr)
/change {
createundofont
3 1 roll
fontset exch get setfont
delim
} def

/b { /b change } def
/i { /i change } def
/r { /r change } def
/t { /t change } def
/@ { (@) part } def

/insertnest 10 dict def

/insertset mark
/verbatim {
2 dict begin
/part { show } def
/heol { eol } def
insertnest /verbatim countdictstack put
}
/quotation {
1 dict begin
/x x .5 inch add def
x Y moveto
insertnest /quotation countdictstack put
}
/verse { }
/example { }
dicttomark def

/enter {
{} %post
{insertset exch get exec} %body
3 -1 roll
delbody
} def

/leave {
{}
{ insertnest exch 2 copy get 3 1 roll
null put
dup null eq { pop }{
countdictstack exch sub
mark exch {currentdict end} repeat
end %merge any cached data up the scope here
% if necessary?!
counttomark {begin} repeat pop
} ifelse
}
3 -1 roll
delbody
} def

/bye {showpage currentfile flushfile clear exit} def


%Manual/Example

default startpage
currentfile cvlit ibis

@b[This is the formatting sample and input playpen:]

Testing the @@ enter/leave(quotation) mechanism.

@enter(quotation)


@t `Lorem ipsum dolor sit amet,' consectataur adipisicing
elit, sed do eiusmod tempor @i[incididunt ut labore] et dolore magna
aliqua. Ut enim @i(ad minim) veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip @i |ex ea commodo| consequat. Duis
aute irure dolor in reprehenderit in voluptate velit @i<esse cillum
dolore eu fugiat nulla pariatur>.

@leave(quotation)

@nextpage

@b[Ibis User Manual]

Introduction

Ibis is a document production program. It is being designed
to mimic the behavior described in the July 1978 CMU
Scribe Introductory Manual that I found through wikipedia.

Ibis is written in postscript and therefore assumes that
it is running in a postscript environment with graphics
devices handled appropriately. It renders text using
postscript graphics primitives. Thus, none of the extensive
device handling performed by Scribe is necessary here.

@enter(quotation)


Paragraphs are separated by blank lines and commands,
if present, are flagged with an "@@ " sign. If you want
an "@@ " sign to appear in your output, you must type two
of them: "@@ @@ ".

@leave(quotation)

Under construction are the insert constructs, currently only
long-form:

@t[@@ enter(quotation)
twinkle, twinkle
little star.
@@ leave(quotation)]

produces

@enter(quotation)
twinkle, twinkle
little star.
@leave(quotation)

@nextpage
Full Postscript source code:

@enter(verbatim) @exit
true { %print source code
clear
/atsign <00> def
fontset /t get setfont
(ibis.ps)(r)file ibis
} if

504(0)03:22 AM:ps 0>

luser- -droog

unread,
May 13, 2011, 2:19:43 AM5/13/11
to
It's true! If you write code as cleverly as possible,
you're not smart enough to debug it. This thing crashes
ghostscript even harder when using my debugger.

I tried rewriting the "ibis" formatting engine. And I
made it pretty and clever and simple and ...
it doesn't work.

Help?

531(1)01:17 AM:ps 0> gs ibis2.ps
GPL Ghostscript 8.62 (2008-02-29)
Copyright (C) 2008 Artifex Software, Inc. All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.
Loading URWPalladioL-Roma font from /var/lib/defoma/gs.d/dirs/fonts/
p052003l.pfb... 2945340 1362355 6814840 5516010 1 done.
initial test
show
this
text please!
Does the
Loading URWPalladioL-Ital font from /var/lib/defoma/gs.d/dirs/fonts/
p052023l.pfb... 3070040 1512423 6834936 5521174 1 done.
italics
Error: /typecheck in --if--
Operand stack:
false ( work?) --nostringval-- --nostringval--
Execution stack:
%interp_exit .runexec2 --nostringval-- --nostringval-- --
nostringval-- 2 %stopped_push --nostringval-- --
nostringval-- --nostringval-- false 1 %stopped_push 1905
1 3 %oparray_pop 1904 1 3 %oparray_pop 1888 1 3
%oparray_pop 1771 1 3 %oparray_pop --nostringval--
%errorexec_pop .runexec2 --nostringval-- --nostringval-- --
nostringval-- 2 %stopped_push --nostringval-- --
nostringval-- --nostringval-- %loop_continue --nostringval--
Dictionary stack:
--dict:1151/1684(ro)(G)-- --dict:0/20(G)-- --dict:
127/200(L)-- --dict:10/14(L)--
Current allocation mode is local
Current file position is 4022
GPL Ghostscript 8.62: Unrecoverable error, exit code 1
532(1)01:17 AM:ps 1> cat ibis2.ps
%!

% Utility

/show { dup print (\n) print show } bind def

/-= { 1 index load exch sub store } def

/dicttomark { % mark k1 v1 .. kN vN dicttomark dict(N)


counttomark 2 idiv dup dict begin
{ def } repeat
pop currentdict end
} def


% Stack type is an array
% where element 0 contains
% the index of the top of the stack
% n stack array{n+1}:[0]=0
/stack { 1 add array dup 0 0 put } def

% Composite Index inc/dec -
% (n.b. userdict is a composite object)
/inc { 2 copy get 1 add put } def
/dec { 2 copy get 1 sub put } def

/push { % S a push - (S{n}->S'{n+1})
1 index 0 inc
1 index 0 get exch put
} def

/peek { dup 0 get get } def % S peek a
/pull { dup peek exch 0 dec } def % S pull a (S{n}->S'(n-1})


% output device
/dev mark
/size [ clippath pathbbox ]
/bounds null
dicttomark def

/savebounds { dev /bounds [ x y X Y ] put } def
/restorebounds { dev /bounds get aload pop setbounds } def

/setbounds { % x y X Y setbounds -


/Y exch def
/X exch def
/y exch def
/x exch def
} def

/setmargin { % pts setmargin -
dev /size get aload pop


4 index sub 4 1 roll
4 index sub 4 1 roll
4 index add 4 1 roll
4 index add 4 1 roll

setbounds pop
savebounds
} def

/nextpage { showpage restorebounds } def


% text setting
/text mark
/eol { /Y lead -=
y Y lt { x Y moveto }
{ nextpage } ifelse }
/heol { eol }
/blank { eol }
/settext { show }
dicttomark def


% processing
/find { % {not} {on_b} {on_a} (aXb) (X) find -
search { % n b a (b) (X) (a)
4 1 roll pop % n b (a) a (b)
4 1 roll % n (b) b (a) a
5 -1 roll pop % (b) b (a) a
exec exec
}{ % n b a (a_b)
4 1 roll pop pop % (a_b) n
exec
} ifelse
} def

%{(n)= =}{(b)= =}{(a)= =} (pretextpost) (text) find
%(stack:)= pstack
%quit

/first { % (abc) first (bc) (a)
dup 1 1 index length 1 sub getinterval exch
0 1 getinterval
} def

% delimiter pairs
/pairs mark
([)(]) (<)(>) (\()(\)) ({)(}) (`)(') (:)(;)

dicttomark def

% ([) rhs (])
% (q) rhs (q)
/rhs { pairs exch 2 copy known { get }{ exch pop } ifelse } def

% {on_a} (]) deferal {[{on_a} (])] nest exch push}
% create a save-it-for-later proc
% for the not-found clause of find
/deferal {
2 array astore
[ exch /nest cvx /exch cvx /push cvx ] cvx
} def

% {on_a} ([a]b) delim (b)
/delim {
first rhs % on_a (a]b) (])
3 copy exch pop deferal %not-clause
{} %on_b clause: leave string on stack
5 2 roll
find
} def

% str execute -
/execute { token { exec process }{ BAD_COMMAND } ifelse } def

% the "at" sign indicates the start of an embedded command
/sigil <40> def

/process { % str process -


dup length 0 eq { pop blank }{

{settext} {execute} {settext} 4 3 roll
sigil find
} ifelse
} def

/src null def
/buf 200 string def
/ibis { % file|string ibis -


dup type /stringtype eq { (r) file } if

dup type /filetype ne { NOT_A_FILE } if
/src exch def

{ src buf readline not exch process { exit } if
heol
} loop

showpage
} def

sigil { sigil settext } def % @@


% ([arg]rem) /name short (rem)
/short {
alt exch get % s d
dup /ini get exec % s d ?
exch /fin get % s ? {}
[ 3 1 roll /exec cvx ] cvx exch % undo s
delim
} def

%alterations
/alt 20 dict def

% name dict newalter -
%
% dict should contain 2 procs
% - ini ?
% ? fin -
% where init returns an object that should be
% passed to final
/newalter {
%install in alt dict
2 copy alt 3 1 roll put
%create short-form procedure
pop [ 1 index /short cvx ] cvx def
%create long-form
} def

/i mark
/ini {currentfont /Palatino-Italic 10 selectfont}
/fin {setfont}
dicttomark newalter


/default {
text begin
72 setmargin
/Palatino-Roman 10 selectfont
/lead 12 def
eol
} def

/bye {exch not exch} def

default
currentfile ibis
initial test
show
this
text please!

Does the @i[italics] work?

@bye
(stack:)= pstack()= currentfile flush


Yves Cloutier

unread,
Feb 1, 2015, 9:24:58 PM2/1/15
to
Hi droog,

I was wondering how your progess was with ibis.ps?

I am working on a related project and am very interested in what you have done so far.

regards,

yves
0 new messages