[net.text] sorting in troff

miker@cord.UUCP (Mike Roberson) (07/21/86)

i caught the: \(br\|line-eater\|\(br\l'|0\(rn'\l'|0\(ul'!

abstract: how can items be sorted in troff(nroff)?

explanation: given the definition of the list-begin, list-item,
	and list-end macros, how can i generate a sorted list of
	the first arguments to the list-item macros?

	e.g., given the following pseudo-troff input:

list-begin
list-item arg1
list-item arg1
list-item arg1
list-end
list-sort	\" i.e. produce a sorted list of all arg1s

	what should list-item and list-sort do?

	my problem is best stated as a troff example. the following
	can be run unchanged with troff(nroff):

.\" ---------- begin troff source  ----------
.de lH	\" list header
\&\\$1
..
.de lB	\" list begin
.in +2i
..
.de lI	\" list item
.br
.\"	the next line causes $1 to be a hanging mark
\h'|-1i'\&\\$1\h'|0'\c
..
.de lE	\" list end
.br
.in -2i
..
.de lS	\" output sorted list
.\" what goes here?
..
.lH "this is the header for the following list"
.lB	\" list start
.lI ".ti"
this is some text that i don't care about.
this is even more text that doesn't matter.
.lI ".in"
this is some text that i don't care about.
this is even more text that doesn't matter.
.lI ".br"
this is some text that i don't care about.
this is even more text that doesn't matter.
.lI ".bp"
this is some text that i don't care about.
this is even more text that doesn't matter.
.lE	\" list end
this is some text (after the list) that i don't care about.
this is even more (after the list) text that doesn't matter.
.lS
.\" ---------- end of troff source ----------

finally: I can't (read: i don't want to) call a sub-shell.
	I also can't (read: i really can't) call a pre-
	processor, unfortunately.

	any help, pointers to documentation, people etc.
	would be greatly appreciated.

ADVthanksANCE,
-- 
"Stoneware - prehistoric computers"
Mike "Trust Me" Roberson               UUCP: {ihnp4,cbosgd,akgua}!cord!miker

liam@cs.qmc.ac.uk (William Roberts) (07/24/86)

Summary:
Expires:
Sender:
Followup-To:
Distribution:
Xpath: ukc eagle

In article <320@cord.UUCP> miker@cord.UUCP writes:
>abstract: how can items be sorted in troff(nroff)?
>
>explanation: given the definition of the list-begin, list-item,
>       and list-end macros, how can i generate a sorted list of
>       the first arguments to the list-item macros?
>
>       e.g., given the following pseudo-troff input:
>
>list-begin
>list-item arg1
>list-item arg1
>list-item arg1
>list-end
>list-sort      \" i.e. produce a sorted list of all arg1s
>
>       what should list-item and list-sort do?

(You are joking, aren't you?)

Ignoring the fact that troff doesn't have string comparisons,
just numeric ones, what you need is a way of imitating arrays
in troff so you can do quicksort/bubblesort or whatever.

The way to imitate arrays is to use dynamically constructed
register/string names.  To mimic an array Q with 10 elements and
access Q[i] where i is a suitable numeric register, do things
like

        .nr \n(Q\ni 7           \" Q[i] := 7
        .nr \n(Q\ni \n(Q\n(j    \" Q[i] := Q[j]
        .nr \n(Q2 3             \" Q[2] := 3

or have a string array if you can find some way of comparing
the arguments. To get arrays with more than 0 elements, you
have to encode the subscript into a single character - help is
at hand in the unlikely form of the .af primitive

        .af i a

will give you a 27 element array with index letters 0,a-z
and tricky use of .ie conditionals will give you A-Z as well by
changing the format to a or A as appropriate. Note that .af
doesn't change the way you assign numbers into the register.

Control structures - I can't offhand think of a way to do
iteration directly (Exercise for the readers?) but recursion is
just macro calling and the \$n arguments really are call-by-value
local variables!  Your only problem will be avoiding macro
nesting depth limits, but you have to tackle the sorting of
strings first.

For the paper in which I first saw these crazy ideas used (to
do proper floating keeps, no -ms rubbish here!), look in
Software- Practice & Experience sometime in the past 4 years
(?) for a paper entitled

        "* On the Power of Traps and Diversions*"

Note the use of pattern matching to compensate for failing
memory.  When you have written your sort program, you might
care to tackle the aesthetically valid idea of re-writing troff
in troff......
-- 

William Roberts         ARPA: liam@cs.qmc.ac.uk  (gw: cs.ucl.edu)
Queen Mary College      UUCP: liam@qmc-cs.UUCP
LONDON, UK              Tel:  01-980 4811 ext 3900

john@basser.oz (John Mackin) (07/28/86)

In article <320@cord.UUCP> miker@cord.UUCP (Mike Roberson) writes:

> how can items be sorted in troff(nroff)?

This got a friend and I to thinking.  Once we worked out a way to
compare strings (for other than (in)equality) an insertion sort
was easy, but we were dissatisfied with its performance, so
we wrote a merge-based sort that is n log n.  Both versions follow.

The insertion sort took 55 minutes of user-time on our 780 to sort
a 300 element list; the merge sort does the same list in 17 minutes
(and a 1000 element list in 72 minutes).  Bear in mind, people, troff
isn't sort!  The insertion sort is far simpler and is perfectly adequate
(and considerably faster) for small lists (say up to 20 or so elements
on a 780).

Each sort has the same interface:

	.LS			\" list start
	.LI "key" "data"	\" list item - will be sorted on the key,
				\" and the data goes with it.  they key must
				\" not contain spaces or backslashes.  if
				\" you want a space in the key, put in a
				\" control-E at that point.
	...
	.LE			\" list end - sort the list and invoke
				\" .lo "key" "data"	\" list output
				\" for every item, in order.  the user can
				\" redefine lo to get whatever format is
				\" desired; a basic one is provided.

We make no apology for this code; we wrote it to establish that it
could be done.  It is unfortunate that we did not adopt a more
consistent naming convention; adapting this for use with any
existing macro package is up to you.

If you have spaces in the key, replace them with control-E characters;
they will be output as spaces.

The only other macro in these sources (it is the same in both) that
you are likely to want to call is .sc, the string comparison macro.

	.sc "string1" "string2"

sets the number register R to 1, 0, or -1, depending on whether string1
is lexically less than, equal to, or greater than string2.

Extract the following shell archive using sh.  Then, BEFORE TRYING TO
USE THE MACROS, edit "insert" and "merge" with an editor capable of
handling control characters.  Globally change the string CTRL-E into
a control-E, and the string CTRL-F into a control-F.

To test the macros, try "nroff insert demo | sed 10q | cmp - demo.out".
(The sed is needed because I stripped the traling newlines from demo.out
for posting.)

Have fun!

John Mackin, Basser Department of Computer Science,
	     University of Sydney, Sydney, Australia

john%basser.oz@SEISMO.CSS.GOV
{seismo,hplabs,mcvax,ukc,nttlab}!munnari!basser.oz!john

The following code is the product of a collaboration between
Mark Shand and John Mackin.  You can do what you like with it,
as long as you don't mail us and ask how it works!

# To unbundle, sh this file
echo insert 1>&2
sed 's/.//' >insert <<'//GO.SYSIN DD insert'
-.ds @CTRL-E "0 "
-.ds @! "1 "
-.ds @" "2 "
-.ds @# "3 "
-.ds @$ "4 "
-.ds @% "5 "
-.ds @& "6 "
-.ds @' "7 "
-.ds @( "8 "
-.ds @) "9 "
-.ds @* "10 "
-.ds @+ "11 "
-.ds @, "12 "
-.ds @- "13 "
-.ds @. "14 "
-.ds @/ "15 "
-.ds @0 "16 "
-.ds @1 "17 "
-.ds @2 "18 "
-.ds @3 "19 "
-.ds @4 "20 "
-.ds @5 "21 "
-.ds @6 "22 "
-.ds @7 "23 "
-.ds @8 "24 "
-.ds @9 "25 "
-.ds @: "26 "
-.ds @; "27 "
-.ds @< "28 "
-.ds @= "29 "
-.ds @> "30 "
-.ds @? "31 "
-.ds @@ "32 "
-.ds @A "33 "
-.ds @B "34 "
-.ds @C "35 "
-.ds @D "36 "
-.ds @E "37 "
-.ds @F "38 "
-.ds @G "39 "
-.ds @H "40 "
-.ds @I "41 "
-.ds @J "42 "
-.ds @K "43 "
-.ds @L "44 "
-.ds @M "45 "
-.ds @N "46 "
-.ds @O "47 "
-.ds @P "48 "
-.ds @Q "49 "
-.ds @R "50 "
-.ds @S "51 "
-.ds @T "52 "
-.ds @U "53 "
-.ds @V "54 "
-.ds @W "55 "
-.ds @X "56 "
-.ds @Y "57 "
-.ds @Z "58 "
-.ds @[ "59 "
-.\" this is a bit buggered ds @\e "60 "
-.ds @] "61 "
-.ds @^ "62 "
-.ds @_ "63 "
-.ds @` "64 "
-.ds @a "65 "
-.ds @b "66 "
-.ds @c "67 "
-.ds @d "68 "
-.ds @e "69 "
-.ds @f "70 "
-.ds @g "71 "
-.ds @h "72 "
-.ds @i "73 "
-.ds @j "74 "
-.ds @k "75 "
-.ds @l "76 "
-.ds @m "77 "
-.ds @n "78 "
-.ds @o "79 "
-.ds @p "80 "
-.ds @q "81 "
-.ds @r "82 "
-.ds @s "83 "
-.ds @t "84 "
-.ds @u "85 "
-.ds @v "86 "
-.ds @w "87 "
-.ds @x "88 "
-.ds @y "89 "
-.ds @z "90 "
-.ds @{ "91 "
-.ds @| "92 "
-.ds @} "93 "
-.ds @~ "94 "
-.\"
-.de sc
-.nr S 0
-.if '\\$1\\$2'' .nr R 0
-.if !'\\$1\\$2'' \{\
-.if '\\$1'' .nr R 0-1
-.if !'\\$1'' \{\
-.if '\\$2'' .nr R 1
-.if !'\\$2'' \{\
-.Sc a \\*(@\\$1
-.Sc b \\*(@\\$2
-.if \\*(Ha=\\*(Hb .sc "\\*(Ta" "\\*(Tb"
-.if !\\nS \{\
-.ie \\*(Ha>\\*(Hb .nr R 1
-.el .nr R 0-1
-'br\}
-'br\}
-'br\}
-'br\}
-.nr S 1
-..
-.de Sc
-.ds H\\$1 "\\$2
-.ds T\\$1 "\\$3
-..
-.de lo
-\\$1 --> \\$2
-..
-.de li
-.if \\n(is=0 \{\
-.sc "\\$1" "\\*(ik"
-.if \\nR=1 \{ .nr is 1
-\!.li "\\*(ik" "\\*(it"
-'br\}
-'br\}
-\!.li "\\$1" "\\$2"
-..
-.de LS
-.rm L
-..
-.de LI
-.nr is 0
-.di M
-.ds ik "\\$1
-.ds it "\\$2
-.L
-.di
-.rn M L
-.if \\n(is=0 \{\
-.da L
-\!.li "\\$1" "\\$2"
-.di
-'br\}
-..
-.de LE
-.rn li lt
-.rn lo li
-.nr F \\n(.u
-.nf
-.tr CTRL-E 
-.L
-.tr
-.if \\nF .fi
-.rn li lo
-.rn lt li
-..
//GO.SYSIN DD insert
echo merge 1>&2
sed 's/.//' >merge <<'//GO.SYSIN DD merge'
-.af ml a
-.af sl a
-.af rl a
-.af tl a
-.ds @CTRL-E "0 "
-.ds @! "1 "
-.ds @" "2 "
-.ds @# "3 "
-.ds @$ "4 "
-.ds @% "5 "
-.ds @& "6 "
-.ds @' "7 "
-.ds @( "8 "
-.ds @) "9 "
-.ds @* "10 "
-.ds @+ "11 "
-.ds @, "12 "
-.ds @- "13 "
-.ds @. "14 "
-.ds @/ "15 "
-.ds @0 "16 "
-.ds @1 "17 "
-.ds @2 "18 "
-.ds @3 "19 "
-.ds @4 "20 "
-.ds @5 "21 "
-.ds @6 "22 "
-.ds @7 "23 "
-.ds @8 "24 "
-.ds @9 "25 "
-.ds @: "26 "
-.ds @; "27 "
-.ds @< "28 "
-.ds @= "29 "
-.ds @> "30 "
-.ds @? "31 "
-.ds @@ "32 "
-.ds @A "33 "
-.ds @B "34 "
-.ds @C "35 "
-.ds @D "36 "
-.ds @E "37 "
-.ds @F "38 "
-.ds @G "39 "
-.ds @H "40 "
-.ds @I "41 "
-.ds @J "42 "
-.ds @K "43 "
-.ds @L "44 "
-.ds @M "45 "
-.ds @N "46 "
-.ds @O "47 "
-.ds @P "48 "
-.ds @Q "49 "
-.ds @R "50 "
-.ds @S "51 "
-.ds @T "52 "
-.ds @U "53 "
-.ds @V "54 "
-.ds @W "55 "
-.ds @X "56 "
-.ds @Y "57 "
-.ds @Z "58 "
-.ds @[ "59 "
-.\" this is a bit buggered ds @\e "60 "
-.ds @] "61 "
-.ds @^ "62 "
-.ds @_ "63 "
-.ds @` "64 "
-.ds @a "65 "
-.ds @b "66 "
-.ds @c "67 "
-.ds @d "68 "
-.ds @e "69 "
-.ds @f "70 "
-.ds @g "71 "
-.ds @h "72 "
-.ds @i "73 "
-.ds @j "74 "
-.ds @k "75 "
-.ds @l "76 "
-.ds @m "77 "
-.ds @n "78 "
-.ds @o "79 "
-.ds @p "80 "
-.ds @q "81 "
-.ds @r "82 "
-.ds @s "83 "
-.ds @t "84 "
-.ds @u "85 "
-.ds @v "86 "
-.ds @w "87 "
-.ds @x "88 "
-.ds @y "89 "
-.ds @z "90 "
-.ds @{ "91 "
-.ds @| "92 "
-.ds @} "93 "
-.ds @~ "94 "
-.ds @CTRL-F "95 "
-.\"
-.de sc
-.nr S 0
-.if '\\$1\\$2'' .nr R 0
-.if !'\\$1\\$2'' \{\
-.if '\\$1'' .nr R 0-1
-.if !'\\$1'' \{\
-.if '\\$2'' .nr R 1
-.if !'\\$2'' \{\
-.Sc a \\*(@\\$1
-.Sc b \\*(@\\$2
-.if \\*(Ha=\\*(Hb .sc "\\*(Ta" "\\*(Tb"
-.if !\\nS \{\
-.ie \\*(Ha>\\*(Hb .nr R 1
-.el .nr R 0-1
-'br\}
-'br\}
-'br\}
-'br\}
-.nr S 1
-..
-.de Sc
-.ds H\\$1 "\\$2
-.ds T\\$1 "\\$3
-..
-.de lo
-\\$1 --> \\$2
-..
-.de li
-.ds ik "<none>
-.lr "\\$1"
-.if !'\\$1'CTRL-F' \!.l0 "\\$1" "\\$2"
-.\"if !'\\$1'CTRL-F' .tm li: "\\$1" into \\n(.z
-..
-.\" lr ensures that %0 contains something (which it does by calling lS,
-.\" the logarithmic split macro); then it extracts the keyword
-.\" out of %0.  if the keyword precedes $1 then it outputs the entry, and
-.\" recurs.
-.de lr
-.if \\n(%0=0 .lS
-.rn l% l0
-.%0
-.rn l0 l%
-.sc "\\$1" "\\*(ik"
-.if \\nR=1 \{\
-\!.l0 "\\*(ik" "\\*(it"
-.\"tm lr: "\\*(ik" into \\n(.z
-.nr %0 0
-.lr "\\$1"
-'br\}
-..
-.de l%
-.ds ik "\\$1
-.ds it "\\$2
-..
-.de lS
-.nr sl 0
-.fs
-.rn re l0
-.nr rl 0
-.nr rc 0
-.nr op 0
-.di %0
-.%\\n(sl
-.di
-.rn l0 re
-.rm %\\n(sl
-.nr %\\n(sl 0
-..
-.de re
-\!.l0 "\\$1" "\\$2"
-.nr rc +1
-.if \\n(rc>=\\n(op \{\
-.di
-.nr %\\n(rl 1
-.nr rl +1
-.di %\\n(rl
-.ie \\n(op=0 .nr op 1
-.el .nr op \\n(op*2
-.nr rc 0
-'br\}
-..
-.de fs
-.nr sl +1
-.if \\n(%\\n(sl=0 .fs
-..
-.de LS
-.nr #a 0
-.nr #b 0
-.nr #c 0
-.nr #d 0
-.nr #e 0
-.nr #f 0
-.nr #g 0
-.nr #h 0
-.nr #i 0
-.nr #j 0
-.nr #k 0
-.nr #l 0
-.nr #m 0
-.nr #n 0
-.nr #o 0
-.nr #p 0
-.nr #q 0
-.nr #r 0
-.nr #s 0
-.nr #t 0
-.nr #u 0
-.nr #v 0
-.nr #w 0
-.nr #x 0
-.nr #y 0
-.nr #z 0
-.rm #a
-.rm #b
-.rm #c
-.rm #d
-.rm #e
-.rm #f
-.rm #g
-.rm #h
-.rm #i
-.rm #j
-.rm #k
-.rm #l
-.rm #m
-.rm #n
-.rm #o
-.rm #p
-.rm #q
-.rm #r
-.rm #s
-.rm #t
-.rm #u
-.rm #v
-.rm #w
-.rm #x
-.rm #y
-.rm #z
-..
-.de LI
-.di #0
-\!.l0 "\\$1" "\\$2"
-.di
-.nr ml 1
-.MG
-..
-.de LE
-.nr ml 1
-.rm #0
-.nr tl 27
-.Ft
-.nr tl +1
-.FM
-.rn lo l0
-.nr F \\n(.u
-.nf
-.tr CTRL-E 
-.#0
-.tr
-.if \\nF .fi
-.rn l0 lo
-..
-.\" this macro has one parameter: a single letter giving the name of the
-.\" diversion to merge with #0 producing #1, which is then moved to #0.
-.de Mg
-.nr %0 0
-.nr %a 0
-.nr %b 0
-.nr %c 0
-.nr %d 0
-.nr %e 0
-.nr %f 0
-.nr %g 0
-.nr %h 0
-.nr %i 0
-.nr %j 0
-.nr %k 0
-.nr %l 0
-.nr %m 0
-.nr %n 0
-.nr %o 0
-.nr %p 0
-.nr %q 0
-.nr %r 0
-.nr %s 0
-.nr %t 0
-.nr %u 0
-.nr %v 0
-.nr %w 0
-.nr %x 0
-.nr %y 0
-.nr %z 0
-.rm %a
-.rm %b
-.rm %c
-.rm %d
-.rm %e
-.rm %f
-.rm %g
-.rm %h
-.rm %i
-.rm %j
-.rm %k
-.rm %l
-.rm %m
-.rm %n
-.rm %o
-.rm %p
-.rm %q
-.rm %r
-.rm %s
-.rm %t
-.rm %u
-.rm %v
-.rm %w
-.rm %x
-.rm %y
-.rm %z
-.da #0
-\!.l0 "CTRL-FCTRL-F" "foobaz"
-.da
-.da #\\$1
-\!.li "CTRL-F" "foobaz"
-.da
-.#%
-.di #1
-.#\\$1
-.di
-.rn #1 #0
-..
-.de MG
-.nr M \\n(#\\n(ml
-.if !\\nM \{\
-.    RN \\n(ml
-.    nr #\\n(ml 1
-'br\}
-.if \\nM \{\
-.    Mg \\n(ml
-.    nr #\\n(ml 0
-.    nr ml +1
-.    MG
-'br\}
-..
-.de FM
-.if \\n(#\\n(ml .Mg \\n(ml
-.nr ml +1
-.if !'\\n(ml'\\n(tl' .FM
-..
-.de RN
-.rn lR l0
-.di #\\$1
-.#0
-.di
-.rn l0 lR
-..
-.de lR
-\!.li "\\$1" "\\$2"
-..
-.de #%
-.nr lC 0
-.rn lC l0
-.#0
-.rn l0 lC
-.nr sl 0
-.nr ol 0
-.nr op 0
-.rn ol l0
-.di %%
-.#0
-.di
-.rm %%
-.rn l0 ol
-..
-.de lC
-.nr lC +1
-..
-.de ol
-.if \\n(ol=\\n(op \{\
-.OL
-.di
-.di %\\n(sl
-.nr %\\n(sl 1
-'br\}
-\!.l0 "\\$1" "\\$2"
-.nr ol +1
-..
-.de OL
-.nr sl +1
-.nr ol 0
-.ie \\n(op=0 .nr op 1
-.el .nr op \\n(op*2
-.nr Lc \\n(lC%2
-.nr lC \\n(lC/2
-.if \\n(Lc=0&\\n(lC>0 .OL
-..
-.de Ft
-.nr tl -1
-.if \\n(#\\n(tl=0 .Ft
-..
//GO.SYSIN DD merge
# To unbundle, sh this file
echo demo 1>&2
sed 's/.//' >demo <<'//GO.SYSIN DD demo'
-.LS
-.LI root "Deus ex Machina"
-.LI daemon "System Daemon"
-.LI bin "System Owner"
-.LI sys "System Source"
-.LI s "System Source"
-.LI backup "Backup Spooler"
-.LI man "Unix Manual"
-.LI adm "System Administration"
-.LI usr "User Administration"
-.LI pascal "Pascal Source"
-.LE
//GO.SYSIN DD demo
echo demo.out 1>&2
sed 's/.//' >demo.out <<'//GO.SYSIN DD demo.out'
-adm --> System Administration
-backup --> Backup Spooler
-bin --> System Owner
-daemon --> System Daemon
-man --> Unix Manual
-pascal --> Pascal Source
-root --> Deus ex Machina
-s --> System Source
-sys --> System Source
-usr --> User Administration
//GO.SYSIN DD demo.out
exit 0

roland@moncskermit.oz (Roland Yap) (07/29/86)

In article <719@basser.oz>, john@basser.oz (John Mackin) writes:
> In article <320@cord.UUCP> miker@cord.UUCP (Mike Roberson) writes:
> 
> > how can items be sorted in troff(nroff)?
> 
> ...
> 
> The insertion sort took 55 minutes of user-time on our 780 to sort
> a 300 element list; the merge sort does the same list in 17 minutes
> (and a 1000 element list in 72 minutes).  Bear in mind, people, troff
> isn't sort!  The insertion sort is far simpler and is perfectly adequate
> (and considerably faster) for small lists (say up to 20 or so elements
> on a 780).
> 
My feeling that this job would be much better done by a preprocessor to
[nt]roff. While one can write amazing (and convoluted) macros to
do almost anything, it is not really suitable for algorithms with
interation, arrays etc. Anyway as evidenced above it is rather slow!

It is probably quite easy to write a quick and dirty awk filter
as a preprocessor which may optionally call sort to do the dirty
work. Any volunteers?

	Roland.

-----------------------------------------------------------------------------
Roland Yap	           ACSNET,CSNET:roland@moncskermit.oz	
Dept. of Computer Science  ARPA:roland%moncskermit.oz@seismo.arpa	
Monash University          UUCP: ..!seismo!munnari!moncskermit.oz!roland	
Clayton     		  ...!{decvax,pesnta,vax135}!mulga!moncskermit.oz!roland
Australia 3168
                          moncsbruce can also be substituted for moncskermit

rcd@nbires.UUCP (Dick Dunn) (07/30/86)

> >abstract: how can items be sorted in troff(nroff)?
> >
> >explanation: given the definition of the list-begin, list-item,
> >       and list-end macros, how can i generate a sorted list of
> >       the first arguments to the list-item macros?
> 
> (You are joking, aren't you?)

The original posting MIGHT have been a joke, but I don't think so.  It's a
good question.  Generating indices is very hard to do with troff, since you
can't feed a piece of text out through a pipe to a program and catch the
result.  (At least, I can't find a way to do it.)  You can try to make
multiple passes somehow, but you end up with a messy makefile for your
document that's peculiar to the document structure.  If you try to piece
the document together from files troff'ed separately, it's a mess to get
the page numbering right and entering the index/indices in the TOC is even
worse.  So--if you're not making a humongous index, it would be worth
trying to do it with troff.

> Ignoring the fact that troff doesn't have string comparisons,...

But OUCH!  That, as far as I can see, is the crux of the problem.  Once you
get the comparison, you've obviously got the power you need; the rest is
just a matter of finding the best way to do it.

> ...what you need is a way of imitating arrays
> in troff so you can do quicksort/bubblesort or whatever.

Arrays aren't really necessary.  You could keep the text in a diversion and
use something as simple as an insertion sort:
	List-start initializes the diversion (probably with a dummy entry)
	  and sets up macros to be used to enter the text.
	Each list-item shuffles text from one diversion to a second,
	  inserting its argument at the appropriate point.  The key here is
	  that the diversion contains macro calls for each item entered so
	  far.  The macro that is called compares its argument (the
	  already-entered string) with the new candidate.  If the new
	  candidate sorts ahead, the macro tosses it into the diversion
	  being created (and might reset some macro definitions to speed up
	  the rest of the copy).  In any case, it then tosses its argument
	  into the diversion (appropriately protected and as a macro call).
	  The diversion needs to have a tail entry to force insertion at
	  the end of the list.
	List-end redefines the macro used in the diversion to be something
	  that outputs text appropriately and cleans up the mess.
The insertion sort is, of course, quadratic in the number of items--and the
unit of work is pretty large.  But anything you could come up with at this
level would be expensive for a list of any substantial size (say, more than
a couple dozen items).  At least it doesn't stop working when you run out
of number registers; the limit on diversions is not too bad.

And anyway, it's all just an entertaining exercise unless somebody knows
how to do the string comparison...
-- 
Dick Dunn	{hao,ucbvax,allegra}!nbires!rcd		(303)444-5710 x3086
   ...Never attribute to malice what can be adequately explained by stupidity.

henry@utzoo.UUCP (Henry Spencer) (07/31/86)

> ... When you have written your sort program, you might
> care to tackle the aesthetically valid idea of re-writing troff
> in troff......

This isn't quite the same thing, but may be amusing.  I actually wrote
(in awk) a "text preprocessor" for troff at one point.  It did the same
sort of thing for ordinary text that eqn does for equations:  emit it as
detailed instructions for troff, checking to see whether a line was full
or not, doing line breaks, etc.  Worked all right.  Not useful, but fun.
-- 
EDEC:  Stupidly non-standard
brain-damaged incompatible	Henry Spencer @ U of Toronto Zoology
proprietary protocol used.	{allegra,ihnp4,decvax,pyramid}!utzoo!henry

liam@cs.qmc.ac.uk (William Roberts) (08/04/86)

In article <7005@utzoo.UUCP> henry@utzoo.UUCP writes:

>I actually wrote
>(in awk) a "text preprocessor" for troff at one point.  It did the same
>sort of thing for ordinary text that eqn does for equations:  emit it as
>detailed instructions for troff, checking to see whether a line was full
>or not, doing line breaks, etc.  Worked all right.  Not useful, but fun.

In a recent paper about his version of Knuth's WEB system,
adapted for use with C and troff, Harold Thimbleby observes
that "The code which did the formatting for a draft printer was
about the same size as the code which prepared the same file to
be formatted by troff. Telling troff what to do is as hard as
actually doing it."

He also mentioned having once written a troff program to
produce Pascal7s triangle - at least the formatting of the
result was easier than in Pascal!

-- 

William Roberts         ARPA: liam@cs.qmc.ac.uk  (gw: cs.ucl.edu)
Queen Mary College      UUCP: liam@qmc-cs.UUCP
LONDON, UK              Tel:  01-980 4811 ext 3900