xref: /csrg-svn/lib/libc/vax/stdio.old/doprnt.c (revision 2041)
1*2041Swnj /* @(#)doprnt.c	4.1 (Berkeley) 12/21/80 */
2*2041Swnj 	# C library -- conversions
3*2041Swnj 
4*2041Swnj .globl	__doprnt
5*2041Swnj .globl	__flsbuf
6*2041Swnj 
7*2041Swnj #define vbit 1
8*2041Swnj #define flags r10
9*2041Swnj #define ndfnd 0
10*2041Swnj #define prec 1
11*2041Swnj #define zfill 2
12*2041Swnj #define minsgn 3
13*2041Swnj #define plssgn 4
14*2041Swnj #define numsgn 5
15*2041Swnj #define caps 6
16*2041Swnj #define blank 7
17*2041Swnj #define gflag 8
18*2041Swnj #define dpflag 9
19*2041Swnj #define width r9
20*2041Swnj #define ndigit r8
21*2041Swnj #define llafx r7
22*2041Swnj #define lrafx r6
23*2041Swnj #define fdesc -4(fp)
24*2041Swnj #define exp -8(fp)
25*2041Swnj #define sexp -12(fp)
26*2041Swnj #define nchar -16(fp)
27*2041Swnj #define sign -17(fp)
28*2041Swnj 	.set ch.zer,'0			# cpp doesn't like single appostrophes
29*2041Swnj 
30*2041Swnj 	.align 2
31*2041Swnj strtab:		# translate table for detecting null and percent
32*2041Swnj 	.byte	0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
33*2041Swnj 	.byte	16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
34*2041Swnj 	.byte	' ,'!,'",'#,'$, 0,'&,'','(,'),'*,'+,',,'-,'.,'/
35*2041Swnj 	.byte	'0,'1,'2,'3,'4,'5,'6,'7,'8,'9,':,';,'<,'=,'>,'?
36*2041Swnj 	.byte	'@,'A,'B,'C,'D,'E,'F,'G,'H,'I,'J,'K,'L,'M,'N,'O
37*2041Swnj 	.byte	'P,'Q,'R,'S,'T,'U,'V,'W,'X,'Y,'Z,'[,'\,'],'^,'_
38*2041Swnj 	.byte	'`,'a,'b,'c,'d,'e,'f,'g,'h,'i,'j,'k,'l,'m,'n,'o
39*2041Swnj 	.byte	'p,'q,'r,'s,'t,'u,'v,'w,'x,'y,'z,'{,'|,'},'~,127
40*2041Swnj 	.byte	128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143
41*2041Swnj 	.byte	144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159
42*2041Swnj 	.byte	160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175
43*2041Swnj 	.byte	176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191
44*2041Swnj 	.byte	192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207
45*2041Swnj 	.byte	208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223
46*2041Swnj 	.byte	224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239
47*2041Swnj 	.byte	240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
48*2041Swnj 
49*2041Swnj strfoo:
50*2041Swnj 	clrl r4					# fix interrupt race
51*2041Swnj 	jbr strok				# and try again
52*2041Swnj strmore:
53*2041Swnj 	movzbl (r1)+,r2			# one char
54*2041Swnj 	tstb (r3)[r2]			# translate
55*2041Swnj 	jeql stresc2			# bad guy in disguise (outbuf is full)
56*2041Swnj strout2:		# enter here to force out r2; r0,r1 must be set
57*2041Swnj 	pushr $3				# save input descriptor
58*2041Swnj 	pushl fdesc				# FILE
59*2041Swnj 	pushl r2				# the char
60*2041Swnj 	calls $2,__flsbuf		# please empty the buffer and handle 1 char
61*2041Swnj 	tstl r0					# successful?
62*2041Swnj 	jgeq strm1				# yes
63*2041Swnj 	jbcs $31,nchar,strm1	# turn on sign bit of nchar to signify error
64*2041Swnj strm1:
65*2041Swnj 	incl nchar				# count the char
66*2041Swnj 	popr $3					# get input descriptor back
67*2041Swnj strout:			# enter via bsb with (r0,r1)=input descriptor
68*2041Swnj 	movab strtab,r3			# table address
69*2041Swnj 	movq *fdesc,r4			# output descriptor
70*2041Swnj 	jbs $31,r4,strfoo		# negative count is a no no
71*2041Swnj strok:
72*2041Swnj 	addl2 r0,nchar			# we intend to move this many chars
73*2041Swnj 	movtuc r0,(r1),$0,(r3),r4,(r5)
74*2041Swnj 	movpsl r2				# squirrel away condition codes
75*2041Swnj 	movq r4,*fdesc			# update output descriptor
76*2041Swnj 	subl2 r0,nchar			# some chars not moved
77*2041Swnj 	jbs $vbit,r2,stresc		# terminated by escape?
78*2041Swnj 	sobgeq r0,strmore		# no; but out buffer might be full
79*2041Swnj stresc:
80*2041Swnj 	rsb
81*2041Swnj stresc2:
82*2041Swnj 	incl r0					# fix the length
83*2041Swnj 	decl r1					# and the addr
84*2041Swnj 	movl $1<vbit,r2			# fake condition codes
85*2041Swnj 	rsb
86*2041Swnj 
87*2041Swnj errdone:
88*2041Swnj 	jbcs $31,nchar,prdone	# set error bit
89*2041Swnj prdone:
90*2041Swnj 	movl nchar,r0
91*2041Swnj 	ret
92*2041Swnj 
93*2041Swnj 	.align	1
94*2041Swnj __doprnt:
95*2041Swnj 	.word	0xfc0			# uses r11-r6
96*2041Swnj 	movab -256(sp),sp		# work space
97*2041Swnj 	movl 4(ap),r11			# addr of format string
98*2041Swnj 	movl 12(ap),fdesc		# output FILE ptr
99*2041Swnj 	movl 8(ap),ap			# addr of first arg
100*2041Swnj 	clrl nchar				# number of chars transferred
101*2041Swnj loop:
102*2041Swnj 	movzwl $65535,r0		# pseudo length
103*2041Swnj 	movl r11,r1				# fmt addr
104*2041Swnj 	bsbw strout				# copy to output, stop at null or percent
105*2041Swnj 	movl r1,r11				# new fmt
106*2041Swnj 	jbc $vbit,r2,loop		# if no escape, then very long fmt
107*2041Swnj 	tstb (r11)+				# escape; null or percent?
108*2041Swnj 	jeql prdone				# null means end of fmt
109*2041Swnj 
110*2041Swnj 	movl sp,r5			# reset output buffer pointer
111*2041Swnj 	clrq r9				# width; flags
112*2041Swnj 	clrq r6				# lrafx,llafx
113*2041Swnj longorunsg:				# we can ignore both of these distinctions
114*2041Swnj short:
115*2041Swnj L4a:
116*2041Swnj 	movzbl (r11)+,r0		# so capital letters can tail merge
117*2041Swnj L4:	caseb r0,$' ,$'x-' 		# format char
118*2041Swnj L5:
119*2041Swnj 	.word space-L5			# space
120*2041Swnj 	.word fmtbad-L5			# !
121*2041Swnj 	.word fmtbad-L5			# "
122*2041Swnj 	.word sharp-L5			# #
123*2041Swnj 	.word fmtbad-L5			# $
124*2041Swnj 	.word fmtbad-L5			# %
125*2041Swnj 	.word fmtbad-L5			# &
126*2041Swnj 	.word fmtbad-L5			# '
127*2041Swnj 	.word fmtbad-L5			# (
128*2041Swnj 	.word fmtbad-L5			# )
129*2041Swnj 	.word indir-L5			# *
130*2041Swnj 	.word plus-L5			# +
131*2041Swnj 	.word fmtbad-L5			# ,
132*2041Swnj 	.word minus-L5			# -
133*2041Swnj 	.word dot-L5			# .
134*2041Swnj 	.word fmtbad-L5			# /
135*2041Swnj 	.word gnum0-L5			# 0
136*2041Swnj 	.word gnum-L5			# 1
137*2041Swnj 	.word gnum-L5			# 2
138*2041Swnj 	.word gnum-L5			# 3
139*2041Swnj 	.word gnum-L5			# 4
140*2041Swnj 	.word gnum-L5			# 5
141*2041Swnj 	.word gnum-L5			# 6
142*2041Swnj 	.word gnum-L5			# 7
143*2041Swnj 	.word gnum-L5			# 8
144*2041Swnj 	.word gnum-L5			# 9
145*2041Swnj 	.word fmtbad-L5			# :
146*2041Swnj 	.word fmtbad-L5			# ;
147*2041Swnj 	.word fmtbad-L5			# <
148*2041Swnj 	.word fmtbad-L5			# =
149*2041Swnj 	.word fmtbad-L5			# >
150*2041Swnj 	.word fmtbad-L5			# ?
151*2041Swnj 	.word fmtbad-L5			# @
152*2041Swnj 	.word fmtbad-L5			# A
153*2041Swnj 	.word fmtbad-L5			# B
154*2041Swnj 	.word fmtbad-L5			# C
155*2041Swnj 	.word decimal-L5		# D
156*2041Swnj 	.word capital-L5		# E
157*2041Swnj 	.word fmtbad-L5			# F
158*2041Swnj 	.word capital-L5		# G
159*2041Swnj 	.word fmtbad-L5			# H
160*2041Swnj 	.word fmtbad-L5			# I
161*2041Swnj 	.word fmtbad-L5			# J
162*2041Swnj 	.word fmtbad-L5			# K
163*2041Swnj 	.word fmtbad-L5			# L
164*2041Swnj 	.word fmtbad-L5			# M
165*2041Swnj 	.word fmtbad-L5			# N
166*2041Swnj 	.word octal-L5			# O
167*2041Swnj 	.word fmtbad-L5			# P
168*2041Swnj 	.word fmtbad-L5			# Q
169*2041Swnj 	.word fmtbad-L5			# R
170*2041Swnj 	.word fmtbad-L5			# S
171*2041Swnj 	.word fmtbad-L5			# T
172*2041Swnj 	.word unsigned-L5		# U
173*2041Swnj 	.word fmtbad-L5			# V
174*2041Swnj 	.word fmtbad-L5			# W
175*2041Swnj 	.word hex-L5			# X
176*2041Swnj 	.word fmtbad-L5			# Y
177*2041Swnj 	.word fmtbad-L5			# Z
178*2041Swnj 	.word fmtbad-L5			# [
179*2041Swnj 	.word fmtbad-L5			# \
180*2041Swnj 	.word fmtbad-L5			# ]
181*2041Swnj 	.word fmtbad-L5			# ^
182*2041Swnj 	.word fmtbad-L5			# _
183*2041Swnj 	.word fmtbad-L5			# `
184*2041Swnj 	.word fmtbad-L5			# a
185*2041Swnj 	.word fmtbad-L5			# b
186*2041Swnj 	.word charac-L5			# c
187*2041Swnj 	.word decimal-L5		# d
188*2041Swnj 	.word scien-L5			# e
189*2041Swnj 	.word float-L5			# f
190*2041Swnj 	.word general-L5		# g
191*2041Swnj 	.word short-L5			# h
192*2041Swnj 	.word fmtbad-L5			# i
193*2041Swnj 	.word fmtbad-L5			# j
194*2041Swnj 	.word fmtbad-L5			# k
195*2041Swnj 	.word longorunsg-L5		# l
196*2041Swnj 	.word fmtbad-L5			# m
197*2041Swnj 	.word fmtbad-L5			# n
198*2041Swnj 	.word octal-L5			# o
199*2041Swnj 	.word fmtbad-L5			# p
200*2041Swnj 	.word fmtbad-L5			# q
201*2041Swnj 	.word fmtbad-L5			# r
202*2041Swnj 	.word string-L5			# s
203*2041Swnj 	.word fmtbad-L5			# t
204*2041Swnj 	.word unsigned-L5		# u
205*2041Swnj 	.word fmtbad-L5			# v
206*2041Swnj 	.word fmtbad-L5			# w
207*2041Swnj 	.word hex-L5			# x
208*2041Swnj fmtbad:
209*2041Swnj 	movb r0,(r5)+			# print the unfound character
210*2041Swnj 	jeql errdone			# dumb users who end the format with a %
211*2041Swnj 	jbr prbuf
212*2041Swnj capital:
213*2041Swnj 	bisl2 $1<caps,flags		# note that it was capitalized
214*2041Swnj 	xorb2 $'a^'A,r0			# make it small
215*2041Swnj 	jbr L4					# and try again
216*2041Swnj 
217*2041Swnj string:
218*2041Swnj 	movl ndigit,r0
219*2041Swnj 	jbs $prec,flags,L20		# max length was specified
220*2041Swnj 	mnegl $1,r0			# default max length
221*2041Swnj L20:	movl (ap)+,r2			# addr first byte
222*2041Swnj 	locc $0,r0,(r2)			# find the zero at the end
223*2041Swnj 	movl r1,r5			# addr last byte +1
224*2041Swnj 	movl r2,r1			# addr first byte
225*2041Swnj 	jbr prstr
226*2041Swnj 
227*2041Swnj htab:	.byte	'0,'1,'2,'3,'4,'5,'6,'7,'8,'9,'a,'b,'c,'d,'e,'f
228*2041Swnj Htab:	.byte	'0,'1,'2,'3,'4,'5,'6,'7,'8,'9,'A,'B,'C,'D,'E,'F
229*2041Swnj 
230*2041Swnj octal:
231*2041Swnj 	movl $30,r2			# init position
232*2041Swnj 	movl $3,r3			# field width
233*2041Swnj 	movab htab,llafx	# translate table
234*2041Swnj 	jbr L10
235*2041Swnj 
236*2041Swnj hex:
237*2041Swnj 	movl $28,r2			# init position
238*2041Swnj 	movl $4,r3			# field width
239*2041Swnj 	movab htab,llafx	# translate table
240*2041Swnj 	jbc $caps,flags,L10
241*2041Swnj 	movab Htab,llafx
242*2041Swnj L10:	mnegl r3,r6			# increment
243*2041Swnj 	clrl r1
244*2041Swnj 	addl2 $4,r5			# room for left affix (2) and slop [forced sign?]
245*2041Swnj 	movl (ap)+,r0			# fetch arg
246*2041Swnj L11:	extzv r2,r3,r0,r1		# pull out a digit
247*2041Swnj 	movb (llafx)[r1],(r5)+		# convert to character
248*2041Swnj L12:	acbl $0,r6,r2,L11		# continue until done
249*2041Swnj 	clrq r6				# lrafx, llafx
250*2041Swnj 	clrb (r5)			# flag end
251*2041Swnj 	skpc $'0,$11,4(sp)		# skip over leading zeroes
252*2041Swnj 	jbc $numsgn,flags,prn3	# easy if no left affix
253*2041Swnj 	tstl -4(ap)				# original value
254*2041Swnj 	jeql prn3			# no affix on 0, for some reason
255*2041Swnj 	cmpl r3,$4			# were we doing hex or octal?
256*2041Swnj 	jneq L12a			# octal
257*2041Swnj 	movb $'x,r0
258*2041Swnj 	jbc $caps,flags,L12b
259*2041Swnj 	movb $'X,r0
260*2041Swnj L12b:	movb r0,-(r1)
261*2041Swnj 	movl $2,llafx		# leading 0x for hex is an affix
262*2041Swnj L12a:	movb $'0,-(r1)	# leading zero for octal is a digit, not an affix
263*2041Swnj 	jbr prn3			# omit sign (plus, blank) massaging
264*2041Swnj 
265*2041Swnj unsigned:
266*2041Swnj lunsigned:
267*2041Swnj 	bicl2 $1<plssgn|1<blank,flags	# omit sign (plus, blank) massaging
268*2041Swnj 	extzv $1,$31,(ap),r0		# right shift logical 1 bit
269*2041Swnj 	cvtlp r0,$10,(sp)		# convert [n/2] to packed
270*2041Swnj 	movp $10,(sp),8(sp)		# copy packed
271*2041Swnj 	addp4 $10,8(sp),$10,(sp)	# 2*[n/2] in packed, at (sp)
272*2041Swnj 	blbc (ap)+,L14			# n was even
273*2041Swnj 	addp4 $1,pone,$10,(sp)		# n was odd
274*2041Swnj 	jbr L14
275*2041Swnj 
276*2041Swnj patdec:					# editpc pattern for decimal printing
277*2041Swnj 	.byte 0xAA			# eo$float 10
278*2041Swnj 	.byte 0x01			# eo$end_float
279*2041Swnj 	.byte 0				# eo$end
280*2041Swnj 
281*2041Swnj decimal:
282*2041Swnj 	cvtlp (ap)+,$10,(sp)		# 10 digits max
283*2041Swnj 	jgeq L14
284*2041Swnj 	incl llafx			# minus sign is a left affix
285*2041Swnj L14:	editpc $10,(sp),patdec,8(sp)	# ascii at 8(sp); r5=end+1
286*2041Swnj 	skpc $' ,$11,8(sp)		# skip leading blanks; r1=first
287*2041Swnj 
288*2041Swnj prnum:			# r1=addr first byte, r5=addr last byte +1, llafx=size of signs
289*2041Swnj 				# -1(r1) vacant, for forced sign
290*2041Swnj 	tstl llafx
291*2041Swnj 	jneq prn3			# already some left affix, dont fuss
292*2041Swnj 	jbc $plssgn,flags,prn2
293*2041Swnj 	movb $'+,-(r1)		# needs a plus sign
294*2041Swnj 	jbr prn4
295*2041Swnj prn2:	jbc $blank,flags,prn3
296*2041Swnj 	movb $' ,-(r1)		# needs a blank sign
297*2041Swnj prn4:	incl llafx
298*2041Swnj prn3:	jbs $prec,flags,prn1
299*2041Swnj 	movl $1,ndigit		# default precision is 1
300*2041Swnj prn1:	subl3 r1,r5,lrafx	# raw width
301*2041Swnj 	subl2 llafx,lrafx	# number of digits
302*2041Swnj 	subl2 lrafx,ndigit	# number of leading zeroes needed
303*2041Swnj 	jleq prstr			# none
304*2041Swnj 	addl2 llafx,r1		# where current digits start
305*2041Swnj 	pushl r1			# movcx gobbles registers
306*2041Swnj 		# check bounds on users who say %.300d
307*2041Swnj 	movab 32(r5)[ndigit],r2
308*2041Swnj 	subl2 fp,r2
309*2041Swnj 	jlss prn5
310*2041Swnj 	subl2 r2,ndigit
311*2041Swnj prn5:
312*2041Swnj 		#
313*2041Swnj 	movc3 lrafx,(r1),(r1)[ndigit]	# make room in middle
314*2041Swnj 	movc5 $0,(r1),$ch.zer,ndigit,*(sp)	# '0 fill
315*2041Swnj 	subl3 llafx,(sp)+,r1	# first byte addr
316*2041Swnj 	addl3 lrafx,r3,r5	# last byte addr +1
317*2041Swnj 
318*2041Swnj prstr:			# r1=addr first byte; r5=addr last byte +1
319*2041Swnj 				# width=minimum width; llafx=len. left affix
320*2041Swnj 				# ndigit=<avail>
321*2041Swnj 	subl3 r1,r5,ndigit		# raw width
322*2041Swnj 	subl3 ndigit,width,r0	# pad length
323*2041Swnj 	jleq padlno				# in particular, no left padding
324*2041Swnj 	jbs $minsgn,flags,padlno
325*2041Swnj 			# extension for %0 flag causing left zero padding to field width
326*2041Swnj 	jbs $zfill,flags,padlz
327*2041Swnj 			# this bsbb needed even if %0 flag extension is removed
328*2041Swnj 	bsbb padb				# blank pad on left
329*2041Swnj 	jbr padnlz
330*2041Swnj padlz:
331*2041Swnj 	movl llafx,r0
332*2041Swnj 	jleq padnlx				# left zero pad requires left affix first
333*2041Swnj 	subl2 r0,ndigit			# part of total length will be transferred
334*2041Swnj 	subl2 r0,width			# and will account for part of minimum width
335*2041Swnj 	bsbw strout				# left affix
336*2041Swnj padnlx:
337*2041Swnj 	subl3 ndigit,width,r0	# pad length
338*2041Swnj 	bsbb padz				# zero pad on left
339*2041Swnj padnlz:
340*2041Swnj 			# end of extension for left zero padding
341*2041Swnj padlno:			# remaining: root, possible right padding
342*2041Swnj 	subl2 ndigit,width		# root reduces minimum width
343*2041Swnj 	movl ndigit,r0			# root length
344*2041Swnj p1:	bsbw strout				# transfer to output buffer
345*2041Swnj p3:	jbc $vbit,r2,padnpct	# percent sign (or null byte via %c) ?
346*2041Swnj 	decl r0					# yes; adjust count
347*2041Swnj 	movzbl (r1)+,r2			# fetch byte
348*2041Swnj 	movq *fdesc,r4			# output buffer descriptor
349*2041Swnj 	sobgeq r4,p2			# room at the out [inn] ?
350*2041Swnj 	bsbw strout2			# no; force it, then try rest
351*2041Swnj 	jbr p3					# here we go 'round the mullberry bush, ...
352*2041Swnj p2:	movb r2,(r5)+			# hand-deposit the percent or null
353*2041Swnj 	incl nchar				# count it
354*2041Swnj 	movq r4,*fdesc			# store output descriptor
355*2041Swnj 	jbr p1					# what an expensive hiccup!
356*2041Swnj padnpct:
357*2041Swnj 	movl width,r0	# size of pad
358*2041Swnj 	jleq loop
359*2041Swnj 	bsbb padb
360*2041Swnj 	jbr loop
361*2041Swnj 
362*2041Swnj padz:
363*2041Swnj 	movb $'0,r2
364*2041Swnj 	jbr pad
365*2041Swnj padb:
366*2041Swnj 	movb $' ,r2
367*2041Swnj pad:
368*2041Swnj 	subl2 r0,width			# pad width decreases minimum width
369*2041Swnj 	pushl r1				# save non-pad addr
370*2041Swnj 	movl r0,llafx			# remember width of pad
371*2041Swnj 	subl2 r0,sp				# allocate
372*2041Swnj 	movc5 $0,(r0),r2,llafx,(sp)	# create pad string
373*2041Swnj 	movl llafx,r0			# length
374*2041Swnj 	movl sp,r1				# addr
375*2041Swnj 	bsbw strout
376*2041Swnj 	addl2 llafx,sp			# deallocate
377*2041Swnj 	movl (sp)+,r1			# recover non-pad addr
378*2041Swnj 	rsb
379*2041Swnj 
380*2041Swnj pone:	.byte	0x1C			# packed 1
381*2041Swnj 
382*2041Swnj charac:
383*2041Swnj 	movl (ap)+,r0		# word containing the char
384*2041Swnj 	movb r0,(r5)+		# one byte, that's all
385*2041Swnj 
386*2041Swnj prbuf:
387*2041Swnj 	movl sp,r1			# addr first byte
388*2041Swnj 	jbr prstr
389*2041Swnj 
390*2041Swnj space:	bisl2 $1<blank,flags		# constant width e fmt, no plus sign
391*2041Swnj 	jbr L4a
392*2041Swnj sharp:	bisl2 $1<numsgn,flags		# 'self identifying', please
393*2041Swnj 	jbr L4a
394*2041Swnj plus:	bisl2 $1<plssgn,flags		# always print sign for floats
395*2041Swnj 	jbr L4a
396*2041Swnj minus:	bisl2 $1<minsgn,flags		# left justification, please
397*2041Swnj 	jbr L4a
398*2041Swnj gnum0:	jbs $ndfnd,flags,gnum
399*2041Swnj 	jbs $prec,flags,gnump		# ignore when reading precision
400*2041Swnj 	bisl2 $1<zfill,flags		# leading zero fill, please
401*2041Swnj gnum:	jbs $prec,flags,gnump
402*2041Swnj 	moval (width)[width],width	# width *= 5;
403*2041Swnj 	movaw -ch.zer(r0)[width],width	# width = 2*witdh + r0 - '0';
404*2041Swnj 	jbr gnumd
405*2041Swnj gnump:	moval (ndigit)[ndigit],ndigit	# ndigit *= 5;
406*2041Swnj 	movaw -ch.zer(r0)[ndigit],ndigit # ndigit = 2*ndigit + r0 - '0';
407*2041Swnj gnumd:	bisl2 $1<ndfnd,flags		# digit seen
408*2041Swnj 	jbr L4a
409*2041Swnj dot:	clrl ndigit			# start on the precision
410*2041Swnj 	bisl2 $1<prec,flags
411*2041Swnj 	bicl2 $1<ndfnd,flags
412*2041Swnj 	jbr L4a
413*2041Swnj indir:
414*2041Swnj 	jbs $prec,flags,in1
415*2041Swnj 	movl (ap)+,width		# width specified by parameter
416*2041Swnj 	jgeq gnumd
417*2041Swnj 	xorl2 $1<minsgn,flags		# parameterized left adjustment
418*2041Swnj 	mnegl width,width
419*2041Swnj 	jbr gnumd
420*2041Swnj in1:
421*2041Swnj 	movl (ap)+,ndigit		# precision specified by paratmeter
422*2041Swnj 	jgeq gnumd
423*2041Swnj 	mnegl ndigit,ndigit
424*2041Swnj 	jbr gnumd
425*2041Swnj 
426*2041Swnj float:
427*2041Swnj 	jbs $prec,flags,float1
428*2041Swnj 	movl $6,ndigit			# default # digits to right of decpt.
429*2041Swnj float1:	bsbw fltcvt
430*2041Swnj 	addl3 exp,ndigit,r7
431*2041Swnj 	movl r7,r6			# for later "underflow" checking
432*2041Swnj 	bgeq fxplrd
433*2041Swnj 	clrl r7				# poor programmer planning
434*2041Swnj fxplrd:	cmpl r7,$31			# expressible in packed decimal?
435*2041Swnj 	bleq fnarro			# yes
436*2041Swnj 	movl $31,r7
437*2041Swnj fnarro:	subl3 $17,r7,r0			# where to round
438*2041Swnj 	ashp r0,$17,(sp),$5,r7,16(sp)	# do it
439*2041Swnj 	bvc fnovfl
440*2041Swnj 		# band-aid for microcode error (spurious overflow)
441*2041Swnj 	#	clrl r0				# assume even length result
442*2041Swnj 	#	jlbc r7,fleven			# right
443*2041Swnj 	#	movl $4,r0			# odd length result
444*2041Swnj 	#fleven:	cmpv r0,$4,16(sp),$0		# top digit zero iff true overflow
445*2041Swnj 	#	bneq fnovfl
446*2041Swnj 		# end band-aid
447*2041Swnj 	aobleq $0,r6,fnovfl		# if "underflow" then jump
448*2041Swnj 	movl r7,r0
449*2041Swnj 	incl exp
450*2041Swnj 	incl r7
451*2041Swnj 	ashp r0,$1,pone,$0,r7,16(sp)
452*2041Swnj 	ashl $-1,r7,r0			# displ to last byte
453*2041Swnj 	bisb2 sign,16(sp)[r0]		# insert sign
454*2041Swnj fnovfl:
455*2041Swnj 	movab 16(sp),r1		# packed source
456*2041Swnj 	movl r7,r6		# packed length
457*2041Swnj 	pushab prnum	# goto prnum after fall-through call to fedit
458*2041Swnj 
459*2041Swnj 
460*2041Swnj 	# enter via bsb
461*2041Swnj 	#	r1=addr of packed source
462*2041Swnj 	#	   16(r1) used to unpack source
463*2041Swnj 	#	   48(r1) used to construct pattern to unpack source
464*2041Swnj 	#	   48(r1) used to hold result
465*2041Swnj 	#	r6=length of packed source (destroyed)
466*2041Swnj 	#	exp=# digits to left of decimal point (destroyed)
467*2041Swnj 	#	ndigit=# digits to right of decimal point (destroyed)
468*2041Swnj 	#	sign=1 if negative, 0 otherwise
469*2041Swnj 	# stack will be used for work space for pattern and unpacked source
470*2041Swnj 	# exits with
471*2041Swnj 	#	r1=addr of punctuated result
472*2041Swnj 	#	r5=addr of last byte +1
473*2041Swnj 	#	llafx=1 if minus sign inserted, 0 otherwise
474*2041Swnj fedit:
475*2041Swnj 	pushab 48(r1)			# save result addr
476*2041Swnj 	movab 48(r1),r3			# pattern addr
477*2041Swnj 	movb $0x03,(r3)+		# eo$set_signif
478*2041Swnj 	movc5 $0,(r1),$0x91,r6,(r3)	# eo$move 1
479*2041Swnj 	clrb (r3)				# eo$end
480*2041Swnj 	editpc r6,(r1),48(r1),16(r1)	# unpack 'em all
481*2041Swnj 	subl3 r6,r5,r1			# addr unpacked source
482*2041Swnj 	movl (sp),r3			# punctuated output placed here
483*2041Swnj 	clrl llafx
484*2041Swnj 	jlbc sign,f1
485*2041Swnj 	movb $'-,(r3)+		# negative
486*2041Swnj 	incl llafx
487*2041Swnj f1:	movl exp,r0
488*2041Swnj 	jgtr f2
489*2041Swnj 	movb $'0,(r3)+		# must have digit before decimal point
490*2041Swnj 	jbr f3
491*2041Swnj f2:	cmpl r0,r6			# limit on packed length
492*2041Swnj 	jleq f4
493*2041Swnj 	movl r6,r0
494*2041Swnj f4:	subl2 r0,r6			# eat some digits
495*2041Swnj 	subl2 r0,exp		# from the exponent
496*2041Swnj 	movc3 r0,(r1),(r3)	# (most of the) digits to left of decimal point
497*2041Swnj 	movl exp,r0			# need any more?
498*2041Swnj 	jleq f3
499*2041Swnj 	movc5 $0,(r1),$'0,r0,(r3)	# '0 fill
500*2041Swnj f3:	movl ndigit,r0		# # digits to right of decimal point
501*2041Swnj 	jgtr f5
502*2041Swnj 	jbs $numsgn,flags,f5	# no decimal point unless forced
503*2041Swnj 	jbcs $dpflag,flags,f6	# no decimal point
504*2041Swnj f5:	movb $'.,(r3)+		# the decimal point
505*2041Swnj f6:	mnegl exp,r0		# "leading" zeroes to right of decimal point
506*2041Swnj 	jleq f9
507*2041Swnj 	cmpl r0,ndigit		# cant exceed this many
508*2041Swnj 	jleq fa
509*2041Swnj 	movl ndigit,r0
510*2041Swnj fa:	subl2 r0,ndigit
511*2041Swnj 	movc5 $0,(r1),$'0,r0,(r3)
512*2041Swnj f9:	movl ndigit,r0
513*2041Swnj 	cmpl r0,r6			# limit on packed length
514*2041Swnj 	jleq f7
515*2041Swnj 	movl r6,r0
516*2041Swnj f7:	subl2 r0,ndigit		# eat some digits from the fraction
517*2041Swnj 	movc3 r0,(r1),(r3)	# (most of the) digits to right of decimal point
518*2041Swnj 	movl ndigit,r0			# need any more?
519*2041Swnj 	jleq f8
520*2041Swnj 		# check bounds on users who say %.300f
521*2041Swnj 	movab 32(r3)[r0],r2
522*2041Swnj 	subl2 fp,r2
523*2041Swnj 	jlss fb
524*2041Swnj 	subl2 r2,r0			# truncate, willy-nilly
525*2041Swnj 	movl r0,ndigit		# and no more digits later, either
526*2041Swnj fb:
527*2041Swnj 		#
528*2041Swnj 	subl2 r0,ndigit		# eat some digits from the fraction
529*2041Swnj 	movc5 $0,(r1),$'0,r0,(r3)	# '0 fill
530*2041Swnj f8:	movl r3,r5			# addr last byte +1
531*2041Swnj 	popr $1<1			# [movl (sp)+,r1] addr first byte
532*2041Swnj 	rsb
533*2041Swnj 
534*2041Swnj patexp:	.byte	0x03			# eo$set_signif
535*2041Swnj 	.byte	0x44,'e			# eo$insert 'e
536*2041Swnj 	.byte	0x42,'+			# eo$load_plus '+
537*2041Swnj 	.byte	0x04			# eo$store_sign
538*2041Swnj 	.byte	0x92			# eo$move 2
539*2041Swnj 	.byte	0			# eo$end
540*2041Swnj 
541*2041Swnj scien:
542*2041Swnj 	incl ndigit
543*2041Swnj 	jbs $prec,flags,L23
544*2041Swnj 	movl $7,ndigit
545*2041Swnj L23:	bsbw fltcvt			# get packed digits
546*2041Swnj 	movl ndigit,r7
547*2041Swnj 	cmpl r7,$31				# expressible in packed decimal?
548*2041Swnj 	jleq snarro				# yes
549*2041Swnj 	movl $31,r7
550*2041Swnj snarro:	subl3 $17,r7,r0		# rounding position
551*2041Swnj 	ashp r0,$17,(sp),$5,r7,16(sp) # shift and round
552*2041Swnj 	bvc snovfl
553*2041Swnj 		# band-aid for microcode error (spurious overflow)
554*2041Swnj 	#	clrl r0				# assume even length result
555*2041Swnj 	#	jlbc ndigit,sceven		# right
556*2041Swnj 	#	movl $4,r0			# odd length result
557*2041Swnj 	#sceven:	cmpv r0,$4,16(sp),$0		# top digit zero iff true overflow
558*2041Swnj 	#	bneq snovfl
559*2041Swnj 		# end band-aid
560*2041Swnj 	incl exp			# rounding overflowed to 100...
561*2041Swnj 	subl3 $1,r7,r0
562*2041Swnj 	ashp r0,$1,pone,$0,r7,16(sp)
563*2041Swnj 	ashl $-1,r7,r0		# displ to last byte
564*2041Swnj 	bisb2 sign,16(sp)[r0]		# insert sign
565*2041Swnj snovfl:
566*2041Swnj 	jbs $gflag,flags,gfmt		# %g format
567*2041Swnj 	movab 16(sp),r1
568*2041Swnj 	bsbb eedit
569*2041Swnj eexp:
570*2041Swnj 	movl r1,r6		# save fwa from destruction by cvtlp
571*2041Swnj 	subl3 $1,sexp,r0	# 1P exponent
572*2041Swnj 	cvtlp r0,$2,(sp)	# packed
573*2041Swnj 	editpc $2,(sp),patexp,(r5)
574*2041Swnj 	movl r6,r1		# fwa
575*2041Swnj 	jbc $caps,flags,prnum
576*2041Swnj 	xorb2 $'e^'E,-4(r5)
577*2041Swnj 	jbr prnum
578*2041Swnj 
579*2041Swnj eedit:
580*2041Swnj 	movl r7,r6		# packed length
581*2041Swnj 	decl ndigit		# 1 digit before decimal point
582*2041Swnj 	movl exp,sexp	# save from destruction
583*2041Swnj 	movl $1,exp		# and pretend
584*2041Swnj 	jbr fedit
585*2041Swnj 
586*2041Swnj gfmt:
587*2041Swnj 	addl3 $3,exp,r0		# exp is 1 more than e
588*2041Swnj 	jlss gfmte		# (e+1)+3<0, e+4<=-1, e<=-5
589*2041Swnj 	subl2 $3,r0		# exp [==(e+1)]
590*2041Swnj 	cmpl r0,ndigit
591*2041Swnj 	jgtr gfmte		# e+1>n, e>=n
592*2041Swnj gfmtf:
593*2041Swnj 	movl r7,r6
594*2041Swnj 	subl2 r0,ndigit		# n-e-1
595*2041Swnj 	movab 16(sp),r1
596*2041Swnj 	bsbw fedit
597*2041Swnj g1:	jbs $numsgn,flags,g2
598*2041Swnj 	jbs $dpflag,flags,g2	# dont strip if no decimal point
599*2041Swnj g3:	cmpb -(r5),$'0		# strip trailing zeroes
600*2041Swnj 	jeql g3
601*2041Swnj 	cmpb (r5),$'.		# and trailing decimal point
602*2041Swnj 	jeql g2
603*2041Swnj 	incl r5
604*2041Swnj g2:	jbc $gflag,flags,eexp
605*2041Swnj 	jbr prnum
606*2041Swnj gfmte:
607*2041Swnj 	movab 16(sp),r1		# packed source
608*2041Swnj 	bsbw eedit
609*2041Swnj 	jbsc $gflag,flags,g1	# gflag now means "use %f" [hence no exponent]
610*2041Swnj 
611*2041Swnj general:
612*2041Swnj 	jbs $prec,flags,gn1
613*2041Swnj 	movl $6,ndigit		# default precision is 6 significant digits
614*2041Swnj gn1:	tstl ndigit		# cannot allow precision of 0
615*2041Swnj 	jgtr gn2
616*2041Swnj 	movl $1,ndigit		# change 0 to 1, willy-nilly
617*2041Swnj gn2:	jbcs $gflag,flags,L23
618*2041Swnj 	jbr L23			# safety net
619*2041Swnj 
620*2041Swnj 	# convert double-floating at (ap) to 17-digit packed at (sp),
621*2041Swnj 	# set 'sign' and 'exp', advance ap.
622*2041Swnj fltcvt:
623*2041Swnj 	clrb sign
624*2041Swnj 	movd (ap)+,r5
625*2041Swnj 	jeql fzero
626*2041Swnj 	bgtr fpos
627*2041Swnj 	mnegd r5,r5
628*2041Swnj 	incb sign
629*2041Swnj fpos:
630*2041Swnj 	extzv $7,$8,r5,r2		# exponent of 2
631*2041Swnj 	movab -0200(r2),r2		# unbias
632*2041Swnj 	mull2 $59,r2			# 59/196: 3rd convergent continued frac of log10(2)
633*2041Swnj 	jlss eneg
634*2041Swnj 	movab 196(r2),r2
635*2041Swnj eneg:
636*2041Swnj 	movab -98(r2),r2
637*2041Swnj 	divl2 $196,r2
638*2041Swnj 	bsbw expten
639*2041Swnj 	cmpd r0,r5
640*2041Swnj 	bgtr ceil
641*2041Swnj 	incl r2
642*2041Swnj ceil:	movl r2,exp
643*2041Swnj 	mnegl r2,r2
644*2041Swnj 	cmpl r2,$29			# 10^(29+9) is all we can handle
645*2041Swnj 	bleq getman
646*2041Swnj 	muld2 ten16,r5
647*2041Swnj 	subl2 $16,r2
648*2041Swnj getman:	addl2 $9,r2			# -ceil(log10(x)) + 9
649*2041Swnj 	bsbb expten
650*2041Swnj 	emodd r0,r4,r5,r0,r5		# (r0+r4)*r5; r0=int, r5=frac
651*2041Swnj fz1:	cvtlp r0,$9,16(sp)		# leading 9 digits
652*2041Swnj 	ashp $8,$9,16(sp),$0,$17,4(sp)	# as top 9 of 17
653*2041Swnj 	emodd ten8,$0,r5,r0,r5
654*2041Swnj 	cvtlp r0,$8,16(sp)		# trailing 8 digits
655*2041Swnj 		# if precision >= 17, must round here
656*2041Swnj 	movl ndigit,r7			# so figure out what precision is
657*2041Swnj 	pushab scien
658*2041Swnj 	cmpl (sp)+,(sp)
659*2041Swnj 	jleq gm1			# who called us?
660*2041Swnj 	addl2 exp,r7			# float; adjust for exponent
661*2041Swnj gm1:	cmpl r7,$17
662*2041Swnj 	jlss gm2
663*2041Swnj 	cmpd r5,$0d0.5			# must round here; check fraction
664*2041Swnj 	jlss gm2
665*2041Swnj 	bisb2 $0x10,8+4(sp)		# increment l.s. digit
666*2041Swnj gm2:		# end of "round here" code
667*2041Swnj 	addp4 $8,16(sp),$17,4(sp)	# combine leading and trailing
668*2041Swnj 	bisb2 sign,12(sp)		# and insert sign
669*2041Swnj 	rsb
670*2041Swnj fzero:	clrl r0
671*2041Swnj 	movl $1,exp		# 0.000e+00 and 0.000 rather than 0.000e-01 and .000
672*2041Swnj 	jbr fz1
673*2041Swnj 
674*2041Swnj 	.align 2
675*2041Swnj lsb: .long 0x00010000		# lsb in the crazy floating-point format
676*2041Swnj 
677*2041Swnj 	# return 10^r2 as a double float in r0||r1 and 8 extra bits of precision in r4
678*2041Swnj 	# preserve r2, r5||r6
679*2041Swnj expten:
680*2041Swnj 	movd $0d1.0,r0			# begin computing 10^exp10
681*2041Swnj 	clrl r4				# bit counter
682*2041Swnj 	movad ten1,r3			# table address
683*2041Swnj 	tstl r2
684*2041Swnj 	bgeq e10lp
685*2041Swnj 	mnegl r2,r2			# get absolute value
686*2041Swnj 	jbss $6,r2,e10lp		# flag as negative
687*2041Swnj e10lp:	jbc r4,r2,el1			# want this power?
688*2041Swnj 	muld2 (r3),r0			# yes
689*2041Swnj el1:	addl2 $8,r3			# advance to next power
690*2041Swnj 	aobleq $5,r4,e10lp		# through 10^32
691*2041Swnj 	jbcc $6,r2,el2			# correct for negative exponent
692*2041Swnj 	divd3 r0,$0d1.0,r0		# by taking reciprocal
693*2041Swnj 	cmpl $28,r2
694*2041Swnj 	jneq enm28
695*2041Swnj 	addl2 lsb,r1			# 10**-28 needs lsb incremented
696*2041Swnj enm28:	mnegl r2,r2			# original exponent of 10
697*2041Swnj el2:	addl3 $5*8,r2,r3		# negative bit positions are illegal?
698*2041Swnj 	jbc r3,xlsbh-5,eoklsb
699*2041Swnj 	subl2 lsb,r1			# lsb was too high
700*2041Swnj eoklsb:
701*2041Swnj 	movzbl xprec[r2],r4		# 8 extra bits
702*2041Swnj 	rsb
703*2041Swnj 
704*2041Swnj 	# powers of ten
705*2041Swnj 	.align	2
706*2041Swnj ten1:	.word	0x4220,0,0,0
707*2041Swnj ten2:	.word	0x43c8,0,0,0
708*2041Swnj ten4:	.word	0x471c,0x4000,0,0
709*2041Swnj ten8:	.word	0x4dbe,0xbc20,0,0
710*2041Swnj ten16:	.word	0x5b0e,0x1bc9,0xbf04,0
711*2041Swnj ten32:	.word	0x759d,0xc5ad,0xa82b,0x70b6
712*2041Swnj 
713*2041Swnj 	# whether lsb is too high or not
714*2041Swnj 	.byte 1:0,1:0,1:0,1:0,1:1,1:0,1:1,1:0	# -40 thru -33
715*2041Swnj 	.byte 1:0,1:1,1:0,1:0,1:0,1:0,1:1,1:0	# -32 thru -25
716*2041Swnj 	.byte 1:0,1:0,1:1,1:1,1:1,1:1,1:0,1:0	# -24 thru -17
717*2041Swnj 	.byte 1:0,1:1,1:0,1:0,1:1,1:1,1:1,1:1	# -16 thru -9
718*2041Swnj 	.byte 1:1,1:1,1:1,1:0,1:0,1:0,1:0,1:1	# -8  thru -1
719*2041Swnj xlsbh:
720*2041Swnj 	.byte 1:0,1:0,1:0,1:0,1:0,1:0,1:0,1:0	# 0 thru 7
721*2041Swnj 	.byte 1:0,1:0,1:0,1:0,1:0,1:0,1:0,1:0	# 8 thru 15
722*2041Swnj 	.byte 1:0,1:0,1:0,1:0,1:0,1:0,1:0,1:0	# 16 thru 23
723*2041Swnj 	.byte 1:0,1:1,1:1,1:0,1:1,1:1,1:1,1:1	# 24 thru 31
724*2041Swnj 	.byte 1:1,1:1,1:1,1:1,1:1,1:1,1:1    	# 32 thru 38
725*2041Swnj 
726*2041Swnj 	# bytes of extra precision
727*2041Swnj 	.byte           0x56,0x76,0xd3,0x88,0xb5,0x62	# -38 thru -33
728*2041Swnj 	.byte 0xba,0xf5,0x32,0x3e,0x0e,0x48,0xdb,0x51	# -32 thru -25
729*2041Swnj 	.byte 0x53,0x27,0xb1,0xef,0xeb,0xa5,0x07,0x49	# -24 thru -17
730*2041Swnj 	.byte 0x5b,0xd9,0x0f,0x13,0xcd,0xff,0xbf,0x97	# -16 thru -9
731*2041Swnj 	.byte 0xfd,0xbc,0xb6,0x23,0x2c,0x3b,0x0a,0xcd	# -8  thru -1
732*2041Swnj xprec:
733*2041Swnj 	.byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00	# 0  thru 7
734*2041Swnj 	.byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00	# 8  thru 15
735*2041Swnj 	.byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00	# 16 thru 23
736*2041Swnj 	.byte 0x00,0xa0,0xc8,0x3a,0x84,0xe4,0xdc,0x92	# 24 thru 31
737*2041Swnj 	.byte 0x9b,0x00,0xc0,0x58,0xae,0x18,0xef     	# 32 thru 38
738