format.scm 56 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691
  1. ;;;; "format.scm" Common LISP text output formatter for SLIB
  2. ;;; Written 1992-1994 by Dirk Lutzebaeck (lutzeb@cs.tu-berlin.de)
  3. ;;; Assimilated into Guile May 1999
  4. ;;
  5. ;; This code is in the public domain.
  6. ;; Authors of the original version (< 1.4) were Ken Dickey and Aubrey Jaffer.
  7. ;; Please send error reports to bug-guile@gnu.org.
  8. ;; For documentation see slib.texi and format.doc.
  9. ;; For testing load formatst.scm.
  10. ;;
  11. ;; Version 3.0
  12. (define-module (ice-9 format)
  13. :use-module (ice-9 and-let-star)
  14. :autoload (ice-9 pretty-print) (pretty-print)
  15. :replace (format)
  16. :export (format:symbol-case-conv
  17. format:iobj-case-conv
  18. format:expch))
  19. ;;; Configuration ------------------------------------------------------------
  20. (define format:symbol-case-conv #f)
  21. ;; Symbols are converted by symbol->string so the case of the printed
  22. ;; symbols is implementation dependent. format:symbol-case-conv is a
  23. ;; one arg closure which is either #f (no conversion), string-upcase!,
  24. ;; string-downcase! or string-capitalize!.
  25. (define format:iobj-case-conv #f)
  26. ;; As format:symbol-case-conv but applies for the representation of
  27. ;; implementation internal objects.
  28. (define format:expch #\E)
  29. ;; The character prefixing the exponent value in ~e printing.
  30. (define format:floats (provided? 'inexact))
  31. ;; Detects if the scheme system implements flonums (see at eof).
  32. (define format:complex-numbers (provided? 'complex))
  33. ;; Detects if the scheme system implements complex numbers.
  34. (define format:radix-pref (char=? #\# (string-ref (number->string 8 8) 0)))
  35. ;; Detects if number->string adds a radix prefix.
  36. (define format:ascii-non-printable-charnames
  37. '#("nul" "soh" "stx" "etx" "eot" "enq" "ack" "bel"
  38. "bs" "ht" "nl" "vt" "np" "cr" "so" "si"
  39. "dle" "dc1" "dc2" "dc3" "dc4" "nak" "syn" "etb"
  40. "can" "em" "sub" "esc" "fs" "gs" "rs" "us" "space"))
  41. ;;; End of configuration ----------------------------------------------------
  42. (define (format . args)
  43. (letrec
  44. ((format:version "3.0")
  45. (format:port #f) ; curr. format output port
  46. (format:output-col 0) ; curr. format output tty column
  47. (format:flush-output #f) ; flush output at end of formatting
  48. (format:case-conversion #f)
  49. (format:args #f)
  50. (format:pos 0) ; curr. format string parsing position
  51. (format:arg-pos 0) ; curr. format argument position
  52. ; this is global for error presentation
  53. ;; format string and char output routines on format:port
  54. (format:out-str
  55. (lambda (str)
  56. (if format:case-conversion
  57. (display (format:case-conversion str) format:port)
  58. (display str format:port))
  59. (set! format:output-col
  60. (+ format:output-col (string-length str)))))
  61. (format:out-char
  62. (lambda (ch)
  63. (if format:case-conversion
  64. (display (format:case-conversion (string ch))
  65. format:port)
  66. (write-char ch format:port))
  67. (set! format:output-col
  68. (if (char=? ch #\newline)
  69. 0
  70. (+ format:output-col 1)))))
  71. ;;(define (format:out-substr str i n) ; this allocates a new string
  72. ;; (display (substring str i n) format:port)
  73. ;; (set! format:output-col (+ format:output-col n)))
  74. (format:out-substr
  75. (lambda (str i n)
  76. (do ((k i (+ k 1)))
  77. ((= k n))
  78. (write-char (string-ref str k) format:port))
  79. (set! format:output-col (+ format:output-col (- n i)))))
  80. ;;(define (format:out-fill n ch) ; this allocates a new string
  81. ;; (format:out-str (make-string n ch)))
  82. (format:out-fill
  83. (lambda (n ch)
  84. (do ((i 0 (+ i 1)))
  85. ((= i n))
  86. (write-char ch format:port))
  87. (set! format:output-col (+ format:output-col n))))
  88. ;; format's user error handler
  89. (format:error
  90. (lambda args ; never returns!
  91. (let ((format-args format:args)
  92. (port (current-error-port)))
  93. (set! format:error format:intern-error)
  94. (if (and (>= (length format:args) 2)
  95. (string? (cadr format:args)))
  96. (let ((format-string (cadr format-args)))
  97. (if (not (zero? format:arg-pos))
  98. (set! format:arg-pos (- format:arg-pos 1)))
  99. (format port
  100. "~%FORMAT: error with call: (format ~a \"~a<===~a\" ~
  101. ~{~a ~}===>~{~a ~})~% "
  102. (car format:args)
  103. (substring format-string 0 format:pos)
  104. (substring format-string format:pos
  105. (string-length format-string))
  106. (list-head (cddr format:args) format:arg-pos)
  107. (list-tail (cddr format:args) format:arg-pos)))
  108. (format port
  109. "~%FORMAT: error with call: (format~{ ~a~})~% "
  110. format:args))
  111. (apply format port args)
  112. (newline port)
  113. (set! format:error format:error-save)
  114. (format:abort))))
  115. (format:intern-error
  116. (lambda args
  117. ;;if something goes wrong in format:error
  118. (display "FORMAT: INTERNAL ERROR IN FORMAT:ERROR!") (newline)
  119. (display " format args: ") (write format:args) (newline)
  120. (display " error args: ") (write args) (newline)
  121. (set! format:error format:error-save)
  122. (format:abort)))
  123. (format:error-save #f)
  124. (format:format
  125. (lambda args ; the formatter entry
  126. (set! format:args args)
  127. (set! format:arg-pos 0)
  128. (set! format:pos 0)
  129. (if (< (length args) 1)
  130. (format:error "not enough arguments"))
  131. ;; If the first argument is a string, then that's the format string.
  132. ;; (Scheme->C)
  133. ;; In this case, put the argument list in canonical form.
  134. (let ((args (if (string? (car args))
  135. (cons #f args)
  136. args)))
  137. ;; Use this canonicalized version when reporting errors.
  138. (set! format:args args)
  139. (let ((destination (car args))
  140. (arglist (cdr args)))
  141. (cond
  142. ((or (and (boolean? destination) ; port output
  143. destination)
  144. (output-port? destination)
  145. (number? destination))
  146. (format:out (cond
  147. ((boolean? destination) (current-output-port))
  148. ((output-port? destination) destination)
  149. ((number? destination) (current-error-port)))
  150. (car arglist) (cdr arglist)))
  151. ((and (boolean? destination) ; string output
  152. (not destination))
  153. (call-with-output-string
  154. (lambda (port) (format:out port (car arglist) (cdr arglist)))))
  155. (else
  156. (format:error "illegal destination `~a'" destination)))))))
  157. (format:out ; the output handler for a port
  158. (lambda (port fmt args)
  159. (set! format:port port) ; global port for
  160. ; output routines
  161. (set! format:case-conversion #f) ; modifier case
  162. ; conversion procedure
  163. (set! format:flush-output #f) ; ~! reset
  164. (and-let* ((col (port-column port))) ; get current column from port
  165. (set! format:output-col col))
  166. (let ((arg-pos (format:format-work fmt args))
  167. (arg-len (length args)))
  168. (cond
  169. ((> arg-pos arg-len)
  170. (set! format:arg-pos (+ arg-len 1))
  171. (display format:arg-pos)
  172. (format:error "~a missing argument~:p" (- arg-pos arg-len)))
  173. (else
  174. (if format:flush-output (force-output port))
  175. #t)))))
  176. (format:parameter-characters
  177. '(#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9 #\- #\+ #\v #\# #\'))
  178. (format:format-work ; does the formatting work
  179. (lambda (format-string arglist)
  180. (letrec
  181. ((format-string-len (string-length format-string))
  182. (arg-pos 0) ; argument position in arglist
  183. (arg-len (length arglist)) ; number of arguments
  184. (modifier #f) ; 'colon | 'at | 'colon-at | #f
  185. (params '()) ; directive parameter list
  186. (param-value-found #f) ; a directive
  187. ; parameter value
  188. ; found
  189. (conditional-nest 0) ; conditional nesting level
  190. (clause-pos 0) ; last cond. clause
  191. ; beginning char pos
  192. (clause-default #f) ; conditional default
  193. ; clause string
  194. (clauses '()) ; conditional clause
  195. ; string list
  196. (conditional-type #f) ; reflects the
  197. ; contional modifiers
  198. (conditional-arg #f) ; argument to apply the conditional
  199. (iteration-nest 0) ; iteration nesting level
  200. (iteration-pos 0) ; iteration string
  201. ; beginning char pos
  202. (iteration-type #f) ; reflects the
  203. ; iteration modifiers
  204. (max-iterations #f) ; maximum number of
  205. ; iterations
  206. (recursive-pos-save format:pos)
  207. (next-char ; gets the next char
  208. ; from format-string
  209. (lambda ()
  210. (let ((ch (peek-next-char)))
  211. (set! format:pos (+ 1 format:pos))
  212. ch)))
  213. (peek-next-char
  214. (lambda ()
  215. (if (>= format:pos format-string-len)
  216. (format:error "illegal format string")
  217. (string-ref format-string format:pos))))
  218. (one-positive-integer?
  219. (lambda (params)
  220. (cond
  221. ((null? params) #f)
  222. ((and (integer? (car params))
  223. (>= (car params) 0)
  224. (= (length params) 1)) #t)
  225. (else
  226. (format:error
  227. "one positive integer parameter expected")))))
  228. (next-arg
  229. (lambda ()
  230. (if (>= arg-pos arg-len)
  231. (begin
  232. (set! format:arg-pos (+ arg-len 1))
  233. (format:error "missing argument(s)")))
  234. (add-arg-pos 1)
  235. (list-ref arglist (- arg-pos 1))))
  236. (prev-arg
  237. (lambda ()
  238. (add-arg-pos -1)
  239. (if (negative? arg-pos)
  240. (format:error "missing backward argument(s)"))
  241. (list-ref arglist arg-pos)))
  242. (rest-args
  243. (lambda ()
  244. (let loop ((l arglist) (k arg-pos)) ; list-tail definition
  245. (if (= k 0) l (loop (cdr l) (- k 1))))))
  246. (add-arg-pos
  247. (lambda (n)
  248. (set! arg-pos (+ n arg-pos))
  249. (set! format:arg-pos arg-pos)))
  250. (anychar-dispatch ; dispatches the format-string
  251. (lambda ()
  252. (if (>= format:pos format-string-len)
  253. arg-pos ; used for ~? continuance
  254. (let ((char (next-char)))
  255. (cond
  256. ((char=? char #\~)
  257. (set! modifier #f)
  258. (set! params '())
  259. (set! param-value-found #f)
  260. (tilde-dispatch))
  261. (else
  262. (if (and (zero? conditional-nest)
  263. (zero? iteration-nest))
  264. (format:out-char char))
  265. (anychar-dispatch)))))))
  266. (tilde-dispatch
  267. (lambda ()
  268. (cond
  269. ((>= format:pos format-string-len)
  270. (format:out-str "~") ; tilde at end of
  271. ; string is just
  272. ; output
  273. arg-pos) ; used for ~?
  274. ; continuance
  275. ((and (or (zero? conditional-nest)
  276. (memv (peek-next-char) ; find conditional
  277. ; directives
  278. (append '(#\[ #\] #\; #\: #\@ #\^)
  279. format:parameter-characters)))
  280. (or (zero? iteration-nest)
  281. (memv (peek-next-char) ; find iteration
  282. ; directives
  283. (append '(#\{ #\} #\: #\@ #\^)
  284. format:parameter-characters))))
  285. (case (char-upcase (next-char))
  286. ;; format directives
  287. ((#\A) ; Any -- for humans
  288. (set! format:read-proof
  289. (memq modifier '(colon colon-at)))
  290. (format:out-obj-padded (memq modifier '(at colon-at))
  291. (next-arg) #f params)
  292. (anychar-dispatch))
  293. ((#\S) ; Slashified -- for parsers
  294. (set! format:read-proof
  295. (memq modifier '(colon colon-at)))
  296. (format:out-obj-padded (memq modifier '(at colon-at))
  297. (next-arg) #t params)
  298. (anychar-dispatch))
  299. ((#\D) ; Decimal
  300. (format:out-num-padded modifier (next-arg) params 10)
  301. (anychar-dispatch))
  302. ((#\X) ; Hexadecimal
  303. (format:out-num-padded modifier (next-arg) params 16)
  304. (anychar-dispatch))
  305. ((#\O) ; Octal
  306. (format:out-num-padded modifier (next-arg) params 8)
  307. (anychar-dispatch))
  308. ((#\B) ; Binary
  309. (format:out-num-padded modifier (next-arg) params 2)
  310. (anychar-dispatch))
  311. ((#\R)
  312. (if (null? params)
  313. (format:out-obj-padded ; Roman, cardinal,
  314. ; ordinal numerals
  315. #f
  316. ((case modifier
  317. ((at) format:num->roman)
  318. ((colon-at) format:num->old-roman)
  319. ((colon) format:num->ordinal)
  320. (else format:num->cardinal))
  321. (next-arg))
  322. #f params)
  323. (format:out-num-padded ; any Radix
  324. modifier (next-arg) (cdr params) (car params)))
  325. (anychar-dispatch))
  326. ((#\F) ; Fixed-format floating-point
  327. (if format:floats
  328. (format:out-fixed modifier (next-arg) params)
  329. (format:out-str (number->string (next-arg))))
  330. (anychar-dispatch))
  331. ((#\E) ; Exponential floating-point
  332. (if format:floats
  333. (format:out-expon modifier (next-arg) params)
  334. (format:out-str (number->string (next-arg))))
  335. (anychar-dispatch))
  336. ((#\G) ; General floating-point
  337. (if format:floats
  338. (format:out-general modifier (next-arg) params)
  339. (format:out-str (number->string (next-arg))))
  340. (anychar-dispatch))
  341. ((#\$) ; Dollars floating-point
  342. (if format:floats
  343. (format:out-dollar modifier (next-arg) params)
  344. (format:out-str (number->string (next-arg))))
  345. (anychar-dispatch))
  346. ((#\I) ; Complex numbers
  347. (if (not format:complex-numbers)
  348. (format:error
  349. "complex numbers not supported by this scheme system"))
  350. (let ((z (next-arg)))
  351. (if (not (complex? z))
  352. (format:error "argument not a complex number"))
  353. (format:out-fixed modifier (real-part z) params)
  354. (format:out-fixed 'at (imag-part z) params)
  355. (format:out-char #\i))
  356. (anychar-dispatch))
  357. ((#\C) ; Character
  358. (let ((ch (if (one-positive-integer? params)
  359. (integer->char (car params))
  360. (next-arg))))
  361. (if (not (char? ch))
  362. (format:error "~~c expects a character"))
  363. (case modifier
  364. ((at)
  365. (format:out-str (format:char->str ch)))
  366. ((colon)
  367. (let ((c (char->integer ch)))
  368. (if (< c 0)
  369. (set! c (+ c 256))) ; compensate
  370. ; complement
  371. ; impl.
  372. (cond
  373. ((< c #x20) ; assumes that control
  374. ; chars are < #x20
  375. (format:out-char #\^)
  376. (format:out-char
  377. (integer->char (+ c #x40))))
  378. ((>= c #x7f)
  379. (format:out-str "#\\")
  380. (format:out-str
  381. (if format:radix-pref
  382. (let ((s (number->string c 8)))
  383. (substring s 2 (string-length s)))
  384. (number->string c 8))))
  385. (else
  386. (format:out-char ch)))))
  387. (else (format:out-char ch))))
  388. (anychar-dispatch))
  389. ((#\P) ; Plural
  390. (if (memq modifier '(colon colon-at))
  391. (prev-arg))
  392. (let ((arg (next-arg)))
  393. (if (not (number? arg))
  394. (format:error "~~p expects a number argument"))
  395. (if (= arg 1)
  396. (if (memq modifier '(at colon-at))
  397. (format:out-char #\y))
  398. (if (memq modifier '(at colon-at))
  399. (format:out-str "ies")
  400. (format:out-char #\s))))
  401. (anychar-dispatch))
  402. ((#\~) ; Tilde
  403. (if (one-positive-integer? params)
  404. (format:out-fill (car params) #\~)
  405. (format:out-char #\~))
  406. (anychar-dispatch))
  407. ((#\%) ; Newline
  408. (if (one-positive-integer? params)
  409. (format:out-fill (car params) #\newline)
  410. (format:out-char #\newline))
  411. (set! format:output-col 0)
  412. (anychar-dispatch))
  413. ((#\&) ; Fresh line
  414. (if (one-positive-integer? params)
  415. (begin
  416. (if (> (car params) 0)
  417. (format:out-fill (- (car params)
  418. (if (>
  419. format:output-col
  420. 0) 0 1))
  421. #\newline))
  422. (set! format:output-col 0))
  423. (if (> format:output-col 0)
  424. (format:out-char #\newline)))
  425. (anychar-dispatch))
  426. ((#\_) ; Space character
  427. (if (one-positive-integer? params)
  428. (format:out-fill (car params) #\space)
  429. (format:out-char #\space))
  430. (anychar-dispatch))
  431. ((#\/) ; Tabulator character
  432. (if (one-positive-integer? params)
  433. (format:out-fill (car params) #\tab)
  434. (format:out-char #\tab))
  435. (anychar-dispatch))
  436. ((#\|) ; Page seperator
  437. (if (one-positive-integer? params)
  438. (format:out-fill (car params) #\page)
  439. (format:out-char #\page))
  440. (set! format:output-col 0)
  441. (anychar-dispatch))
  442. ((#\T) ; Tabulate
  443. (format:tabulate modifier params)
  444. (anychar-dispatch))
  445. ((#\Y) ; Pretty-print
  446. (pretty-print (next-arg) format:port)
  447. (set! format:output-col 0)
  448. (anychar-dispatch))
  449. ((#\? #\K) ; Indirection (is "~K" in T-Scheme)
  450. (cond
  451. ((memq modifier '(colon colon-at))
  452. (format:error "illegal modifier in ~~?"))
  453. ((eq? modifier 'at)
  454. (let* ((frmt (next-arg))
  455. (args (rest-args)))
  456. (add-arg-pos (format:format-work frmt args))))
  457. (else
  458. (let* ((frmt (next-arg))
  459. (args (next-arg)))
  460. (format:format-work frmt args))))
  461. (anychar-dispatch))
  462. ((#\!) ; Flush output
  463. (set! format:flush-output #t)
  464. (anychar-dispatch))
  465. ((#\newline) ; Continuation lines
  466. (if (eq? modifier 'at)
  467. (format:out-char #\newline))
  468. (if (< format:pos format-string-len)
  469. (do ((ch (peek-next-char) (peek-next-char)))
  470. ((or (not (char-whitespace? ch))
  471. (= format:pos (- format-string-len 1))))
  472. (if (eq? modifier 'colon)
  473. (format:out-char (next-char))
  474. (next-char))))
  475. (anychar-dispatch))
  476. ((#\*) ; Argument jumping
  477. (case modifier
  478. ((colon) ; jump backwards
  479. (if (one-positive-integer? params)
  480. (do ((i 0 (+ i 1)))
  481. ((= i (car params)))
  482. (prev-arg))
  483. (prev-arg)))
  484. ((at) ; jump absolute
  485. (set! arg-pos (if (one-positive-integer? params)
  486. (car params) 0)))
  487. ((colon-at)
  488. (format:error "illegal modifier `:@' in ~~* directive"))
  489. (else ; jump forward
  490. (if (one-positive-integer? params)
  491. (do ((i 0 (+ i 1)))
  492. ((= i (car params)))
  493. (next-arg))
  494. (next-arg))))
  495. (anychar-dispatch))
  496. ((#\() ; Case conversion begin
  497. (set! format:case-conversion
  498. (case modifier
  499. ((at) string-capitalize-first)
  500. ((colon) string-capitalize)
  501. ((colon-at) string-upcase)
  502. (else string-downcase)))
  503. (anychar-dispatch))
  504. ((#\)) ; Case conversion end
  505. (if (not format:case-conversion)
  506. (format:error "missing ~~("))
  507. (set! format:case-conversion #f)
  508. (anychar-dispatch))
  509. ((#\[) ; Conditional begin
  510. (set! conditional-nest (+ conditional-nest 1))
  511. (cond
  512. ((= conditional-nest 1)
  513. (set! clause-pos format:pos)
  514. (set! clause-default #f)
  515. (set! clauses '())
  516. (set! conditional-type
  517. (case modifier
  518. ((at) 'if-then)
  519. ((colon) 'if-else-then)
  520. ((colon-at) (format:error "illegal modifier in ~~["))
  521. (else 'num-case)))
  522. (set! conditional-arg
  523. (if (one-positive-integer? params)
  524. (car params)
  525. (next-arg)))))
  526. (anychar-dispatch))
  527. ((#\;) ; Conditional separator
  528. (if (zero? conditional-nest)
  529. (format:error "~~; not in ~~[~~] conditional"))
  530. (if (not (null? params))
  531. (format:error "no parameter allowed in ~~;"))
  532. (if (= conditional-nest 1)
  533. (let ((clause-str
  534. (cond
  535. ((eq? modifier 'colon)
  536. (set! clause-default #t)
  537. (substring format-string clause-pos
  538. (- format:pos 3)))
  539. ((memq modifier '(at colon-at))
  540. (format:error "illegal modifier in ~~;"))
  541. (else
  542. (substring format-string clause-pos
  543. (- format:pos 2))))))
  544. (set! clauses (append clauses (list clause-str)))
  545. (set! clause-pos format:pos)))
  546. (anychar-dispatch))
  547. ((#\]) ; Conditional end
  548. (if (zero? conditional-nest) (format:error "missing ~~["))
  549. (set! conditional-nest (- conditional-nest 1))
  550. (if modifier
  551. (format:error "no modifier allowed in ~~]"))
  552. (if (not (null? params))
  553. (format:error "no parameter allowed in ~~]"))
  554. (cond
  555. ((zero? conditional-nest)
  556. (let ((clause-str (substring format-string clause-pos
  557. (- format:pos 2))))
  558. (if clause-default
  559. (set! clause-default clause-str)
  560. (set! clauses (append clauses (list clause-str)))))
  561. (case conditional-type
  562. ((if-then)
  563. (if conditional-arg
  564. (format:format-work (car clauses)
  565. (list conditional-arg))))
  566. ((if-else-then)
  567. (add-arg-pos
  568. (format:format-work (if conditional-arg
  569. (cadr clauses)
  570. (car clauses))
  571. (rest-args))))
  572. ((num-case)
  573. (if (or (not (integer? conditional-arg))
  574. (< conditional-arg 0))
  575. (format:error "argument not a positive integer"))
  576. (if (not (and (>= conditional-arg (length clauses))
  577. (not clause-default)))
  578. (add-arg-pos
  579. (format:format-work
  580. (if (>= conditional-arg (length clauses))
  581. clause-default
  582. (list-ref clauses conditional-arg))
  583. (rest-args))))))))
  584. (anychar-dispatch))
  585. ((#\{) ; Iteration begin
  586. (set! iteration-nest (+ iteration-nest 1))
  587. (cond
  588. ((= iteration-nest 1)
  589. (set! iteration-pos format:pos)
  590. (set! iteration-type
  591. (case modifier
  592. ((at) 'rest-args)
  593. ((colon) 'sublists)
  594. ((colon-at) 'rest-sublists)
  595. (else 'list)))
  596. (set! max-iterations (if (one-positive-integer? params)
  597. (car params) #f))))
  598. (anychar-dispatch))
  599. ((#\}) ; Iteration end
  600. (if (zero? iteration-nest) (format:error "missing ~~{"))
  601. (set! iteration-nest (- iteration-nest 1))
  602. (case modifier
  603. ((colon)
  604. (if (not max-iterations) (set! max-iterations 1)))
  605. ((colon-at at) (format:error "illegal modifier")))
  606. (if (not (null? params))
  607. (format:error "no parameters allowed in ~~}"))
  608. (if (zero? iteration-nest)
  609. (let ((iteration-str
  610. (substring format-string iteration-pos
  611. (- format:pos (if modifier 3 2)))))
  612. (if (string=? iteration-str "")
  613. (set! iteration-str (next-arg)))
  614. (case iteration-type
  615. ((list)
  616. (let ((args (next-arg))
  617. (args-len 0))
  618. (if (not (list? args))
  619. (format:error "expected a list argument"))
  620. (set! args-len (length args))
  621. (do ((arg-pos 0 (+ arg-pos
  622. (format:format-work
  623. iteration-str
  624. (list-tail args arg-pos))))
  625. (i 0 (+ i 1)))
  626. ((or (>= arg-pos args-len)
  627. (and max-iterations
  628. (>= i max-iterations)))))))
  629. ((sublists)
  630. (let ((args (next-arg))
  631. (args-len 0))
  632. (if (not (list? args))
  633. (format:error "expected a list argument"))
  634. (set! args-len (length args))
  635. (do ((arg-pos 0 (+ arg-pos 1)))
  636. ((or (>= arg-pos args-len)
  637. (and max-iterations
  638. (>= arg-pos max-iterations))))
  639. (let ((sublist (list-ref args arg-pos)))
  640. (if (not (list? sublist))
  641. (format:error
  642. "expected a list of lists argument"))
  643. (format:format-work iteration-str sublist)))))
  644. ((rest-args)
  645. (let* ((args (rest-args))
  646. (args-len (length args))
  647. (usedup-args
  648. (do ((arg-pos 0 (+ arg-pos
  649. (format:format-work
  650. iteration-str
  651. (list-tail
  652. args arg-pos))))
  653. (i 0 (+ i 1)))
  654. ((or (>= arg-pos args-len)
  655. (and max-iterations
  656. (>= i max-iterations)))
  657. arg-pos))))
  658. (add-arg-pos usedup-args)))
  659. ((rest-sublists)
  660. (let* ((args (rest-args))
  661. (args-len (length args))
  662. (usedup-args
  663. (do ((arg-pos 0 (+ arg-pos 1)))
  664. ((or (>= arg-pos args-len)
  665. (and max-iterations
  666. (>= arg-pos max-iterations)))
  667. arg-pos)
  668. (let ((sublist (list-ref args arg-pos)))
  669. (if (not (list? sublist))
  670. (format:error "expected list arguments"))
  671. (format:format-work iteration-str sublist)))))
  672. (add-arg-pos usedup-args)))
  673. (else (format:error "internal error in ~~}")))))
  674. (anychar-dispatch))
  675. ((#\^) ; Up and out
  676. (let* ((continue
  677. (cond
  678. ((not (null? params))
  679. (not
  680. (case (length params)
  681. ((1) (zero? (car params)))
  682. ((2) (= (list-ref params 0) (list-ref params 1)))
  683. ((3) (<= (list-ref params 0)
  684. (list-ref params 1)
  685. (list-ref params 2)))
  686. (else (format:error "too much parameters")))))
  687. (format:case-conversion ; if conversion stop conversion
  688. (set! format:case-conversion string-copy) #t)
  689. ((= iteration-nest 1) #t)
  690. ((= conditional-nest 1) #t)
  691. ((>= arg-pos arg-len)
  692. (set! format:pos format-string-len) #f)
  693. (else #t))))
  694. (if continue
  695. (anychar-dispatch))))
  696. ;; format directive modifiers and parameters
  697. ((#\@) ; `@' modifier
  698. (if (memq modifier '(at colon-at))
  699. (format:error "double `@' modifier"))
  700. (set! modifier (if (eq? modifier 'colon) 'colon-at 'at))
  701. (tilde-dispatch))
  702. ((#\:) ; `:' modifier
  703. (if (memq modifier '(colon colon-at))
  704. (format:error "double `:' modifier"))
  705. (set! modifier (if (eq? modifier 'at) 'colon-at 'colon))
  706. (tilde-dispatch))
  707. ((#\') ; Character parameter
  708. (if modifier (format:error "misplaced modifier"))
  709. (set! params (append params (list (char->integer (next-char)))))
  710. (set! param-value-found #t)
  711. (tilde-dispatch))
  712. ((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9 #\- #\+) ; num. paramtr
  713. (if modifier (format:error "misplaced modifier"))
  714. (let ((num-str-beg (- format:pos 1))
  715. (num-str-end format:pos))
  716. (do ((ch (peek-next-char) (peek-next-char)))
  717. ((not (char-numeric? ch)))
  718. (next-char)
  719. (set! num-str-end (+ 1 num-str-end)))
  720. (set! params
  721. (append params
  722. (list (string->number
  723. (substring format-string
  724. num-str-beg
  725. num-str-end))))))
  726. (set! param-value-found #t)
  727. (tilde-dispatch))
  728. ((#\V) ; Variable parameter from next argum.
  729. (if modifier (format:error "misplaced modifier"))
  730. (set! params (append params (list (next-arg))))
  731. (set! param-value-found #t)
  732. (tilde-dispatch))
  733. ((#\#) ; Parameter is number of remaining args
  734. (if param-value-found (format:error "misplaced '#'"))
  735. (if modifier (format:error "misplaced modifier"))
  736. (set! params (append params (list (length (rest-args)))))
  737. (set! param-value-found #t)
  738. (tilde-dispatch))
  739. ((#\,) ; Parameter separators
  740. (if modifier (format:error "misplaced modifier"))
  741. (if (not param-value-found)
  742. (set! params (append params '(#f)))) ; append empty paramtr
  743. (set! param-value-found #f)
  744. (tilde-dispatch))
  745. ((#\Q) ; Inquiry messages
  746. (if (eq? modifier 'colon)
  747. (format:out-str format:version)
  748. (let ((nl (string #\newline)))
  749. (format:out-str
  750. (string-append
  751. "SLIB Common LISP format version " format:version nl
  752. " (C) copyright 1992-1994 by Dirk Lutzebaeck" nl
  753. " please send bug reports to `lutzeb@cs.tu-berlin.de'"
  754. nl))))
  755. (anychar-dispatch))
  756. (else ; Unknown tilde directive
  757. (format:error "unknown control character `~c'"
  758. (string-ref format-string (- format:pos 1))))))
  759. (else (anychar-dispatch)))))) ; in case of conditional
  760. (set! format:pos 0)
  761. (set! format:arg-pos 0)
  762. (anychar-dispatch) ; start the formatting
  763. (set! format:pos recursive-pos-save)
  764. arg-pos))) ; return the position in the arg. list
  765. ;; when format:read-proof is true, format:obj->str will wrap
  766. ;; result strings starting with "#<" in an extra pair of double
  767. ;; quotes.
  768. (format:read-proof #f)
  769. ;; format:obj->str returns a R4RS representation as a string of
  770. ;; an arbitrary scheme object.
  771. (format:obj->str
  772. (lambda (obj slashify)
  773. (let ((res (if slashify
  774. (object->string obj)
  775. (with-output-to-string (lambda () (display obj))))))
  776. (if (and format:read-proof (string-prefix? "#<" res))
  777. (object->string res)
  778. res))))
  779. ;; format:char->str converts a character into a slashified string as
  780. ;; done by `write'. The procedure is dependent on the integer
  781. ;; representation of characters and assumes a character number according to
  782. ;; the ASCII character set.
  783. (format:char->str
  784. (lambda (ch)
  785. (let ((int-rep (char->integer ch)))
  786. (if (< int-rep 0) ; if chars are [-128...+127]
  787. (set! int-rep (+ int-rep 256)))
  788. (string-append
  789. "#\\"
  790. (cond
  791. ((char=? ch #\newline) "newline")
  792. ((and (>= int-rep 0) (<= int-rep 32))
  793. (vector-ref format:ascii-non-printable-charnames int-rep))
  794. ((= int-rep 127) "del")
  795. ((>= int-rep 128) ; octal representation
  796. (if format:radix-pref
  797. (let ((s (number->string int-rep 8)))
  798. (substring s 2 (string-length s)))
  799. (number->string int-rep 8)))
  800. (else (string ch)))))))
  801. (format:space-ch (char->integer #\space))
  802. (format:zero-ch (char->integer #\0))
  803. (format:par
  804. (lambda (pars length index default name)
  805. (if (> length index)
  806. (let ((par (list-ref pars index)))
  807. (if par
  808. (if name
  809. (if (< par 0)
  810. (format:error
  811. "~s parameter must be a positive integer" name)
  812. par)
  813. par)
  814. default))
  815. default)))
  816. (format:out-obj-padded
  817. (lambda (pad-left obj slashify pars)
  818. (if (null? pars)
  819. (format:out-str (format:obj->str obj slashify))
  820. (let ((l (length pars)))
  821. (let ((mincol (format:par pars l 0 0 "mincol"))
  822. (colinc (format:par pars l 1 1 "colinc"))
  823. (minpad (format:par pars l 2 0 "minpad"))
  824. (padchar (integer->char
  825. (format:par pars l 3 format:space-ch #f)))
  826. (objstr (format:obj->str obj slashify)))
  827. (if (not pad-left)
  828. (format:out-str objstr))
  829. (do ((objstr-len (string-length objstr))
  830. (i minpad (+ i colinc)))
  831. ((>= (+ objstr-len i) mincol)
  832. (format:out-fill i padchar)))
  833. (if pad-left
  834. (format:out-str objstr)))))))
  835. (format:out-num-padded
  836. (lambda (modifier number pars radix)
  837. (if (not (integer? number)) (format:error "argument not an integer"))
  838. (let ((numstr (number->string number radix)))
  839. (if (and format:radix-pref (not (= radix 10)))
  840. (set! numstr (substring numstr 2 (string-length numstr))))
  841. (if (and (null? pars) (not modifier))
  842. (format:out-str numstr)
  843. (let ((l (length pars))
  844. (numstr-len (string-length numstr)))
  845. (let ((mincol (format:par pars l 0 #f "mincol"))
  846. (padchar (integer->char
  847. (format:par pars l 1 format:space-ch #f)))
  848. (commachar (integer->char
  849. (format:par pars l 2 (char->integer #\,) #f)))
  850. (commawidth (format:par pars l 3 3 "commawidth")))
  851. (if mincol
  852. (let ((numlen numstr-len)) ; calc. the output len of number
  853. (if (and (memq modifier '(at colon-at)) (>= number 0))
  854. (set! numlen (+ numlen 1)))
  855. (if (memq modifier '(colon colon-at))
  856. (set! numlen (+ (quotient (- numstr-len
  857. (if (< number 0) 2 1))
  858. commawidth)
  859. numlen)))
  860. (if (> mincol numlen)
  861. (format:out-fill (- mincol numlen) padchar))))
  862. (if (and (memq modifier '(at colon-at))
  863. (>= number 0))
  864. (format:out-char #\+))
  865. (if (memq modifier '(colon colon-at)) ; insert comma character
  866. (let ((start (remainder numstr-len commawidth))
  867. (ns (if (< number 0) 1 0)))
  868. (format:out-substr numstr 0 start)
  869. (do ((i start (+ i commawidth)))
  870. ((>= i numstr-len))
  871. (if (> i ns)
  872. (format:out-char commachar))
  873. (format:out-substr numstr i (+ i commawidth))))
  874. (format:out-str numstr))))))))
  875. (format:tabulate
  876. (lambda (modifier pars)
  877. (let ((l (length pars)))
  878. (let ((colnum (format:par pars l 0 1 "colnum"))
  879. (colinc (format:par pars l 1 1 "colinc"))
  880. (padch (integer->char (format:par pars l 2 format:space-ch #f))))
  881. (case modifier
  882. ((colon colon-at)
  883. (format:error "unsupported modifier for ~~t"))
  884. ((at) ; relative tabulation
  885. (format:out-fill
  886. (if (= colinc 0)
  887. colnum ; colnum = colrel
  888. (do ((c 0 (+ c colinc))
  889. (col (+ format:output-col colnum)))
  890. ((>= c col)
  891. (- c format:output-col))))
  892. padch))
  893. (else ; absolute tabulation
  894. (format:out-fill
  895. (cond
  896. ((< format:output-col colnum)
  897. (- colnum format:output-col))
  898. ((= colinc 0)
  899. 0)
  900. (else
  901. (do ((c colnum (+ c colinc)))
  902. ((>= c format:output-col)
  903. (- c format:output-col)))))
  904. padch)))))))
  905. ;; roman numerals (from dorai@cs.rice.edu).
  906. (format:roman-alist
  907. '((1000 #\M) (500 #\D) (100 #\C) (50 #\L)
  908. (10 #\X) (5 #\V) (1 #\I)))
  909. (format:roman-boundary-values
  910. '(100 100 10 10 1 1 #f))
  911. (format:num->old-roman
  912. (lambda (n)
  913. (if (and (integer? n) (>= n 1))
  914. (let loop ((n n)
  915. (romans format:roman-alist)
  916. (s '()))
  917. (if (null? romans) (list->string (reverse s))
  918. (let ((roman-val (caar romans))
  919. (roman-dgt (cadar romans)))
  920. (do ((q (quotient n roman-val) (- q 1))
  921. (s s (cons roman-dgt s)))
  922. ((= q 0)
  923. (loop (remainder n roman-val)
  924. (cdr romans) s))))))
  925. (format:error "only positive integers can be romanized"))))
  926. (format:num->roman
  927. (lambda (n)
  928. (if (and (integer? n) (> n 0))
  929. (let loop ((n n)
  930. (romans format:roman-alist)
  931. (boundaries format:roman-boundary-values)
  932. (s '()))
  933. (if (null? romans)
  934. (list->string (reverse s))
  935. (let ((roman-val (caar romans))
  936. (roman-dgt (cadar romans))
  937. (bdry (car boundaries)))
  938. (let loop2 ((q (quotient n roman-val))
  939. (r (remainder n roman-val))
  940. (s s))
  941. (if (= q 0)
  942. (if (and bdry (>= r (- roman-val bdry)))
  943. (loop (remainder r bdry) (cdr romans)
  944. (cdr boundaries)
  945. (cons roman-dgt
  946. (append
  947. (cdr (assv bdry romans))
  948. s)))
  949. (loop r (cdr romans) (cdr boundaries) s))
  950. (loop2 (- q 1) r (cons roman-dgt s)))))))
  951. (format:error "only positive integers can be romanized"))))
  952. ;; cardinals & ordinals (from dorai@cs.rice.edu)
  953. (format:cardinal-ones-list
  954. '(#f "one" "two" "three" "four" "five"
  955. "six" "seven" "eight" "nine" "ten" "eleven" "twelve" "thirteen"
  956. "fourteen" "fifteen" "sixteen" "seventeen" "eighteen"
  957. "nineteen"))
  958. (format:cardinal-tens-list
  959. '(#f #f "twenty" "thirty" "forty" "fifty" "sixty" "seventy" "eighty"
  960. "ninety"))
  961. (format:num->cardinal999
  962. (lambda (n)
  963. ;this procedure is inspired by the Bruno Haible's CLisp
  964. ;function format-small-cardinal, which converts numbers
  965. ;in the range 1 to 999, and is used for converting each
  966. ;thousand-block in a larger number
  967. (let* ((hundreds (quotient n 100))
  968. (tens+ones (remainder n 100))
  969. (tens (quotient tens+ones 10))
  970. (ones (remainder tens+ones 10)))
  971. (append
  972. (if (> hundreds 0)
  973. (append
  974. (string->list
  975. (list-ref format:cardinal-ones-list hundreds))
  976. (string->list" hundred")
  977. (if (> tens+ones 0) '(#\space) '()))
  978. '())
  979. (if (< tens+ones 20)
  980. (if (> tens+ones 0)
  981. (string->list
  982. (list-ref format:cardinal-ones-list tens+ones))
  983. '())
  984. (append
  985. (string->list
  986. (list-ref format:cardinal-tens-list tens))
  987. (if (> ones 0)
  988. (cons #\-
  989. (string->list
  990. (list-ref format:cardinal-ones-list ones)))
  991. '())))))))
  992. (format:cardinal-thousand-block-list
  993. '("" " thousand" " million" " billion" " trillion" " quadrillion"
  994. " quintillion" " sextillion" " septillion" " octillion" " nonillion"
  995. " decillion" " undecillion" " duodecillion" " tredecillion"
  996. " quattuordecillion" " quindecillion" " sexdecillion" " septendecillion"
  997. " octodecillion" " novemdecillion" " vigintillion"))
  998. (format:num->cardinal
  999. (lambda (n)
  1000. (cond ((not (integer? n))
  1001. (format:error
  1002. "only integers can be converted to English cardinals"))
  1003. ((= n 0) "zero")
  1004. ((< n 0) (string-append "minus " (format:num->cardinal (- n))))
  1005. (else
  1006. (let ((power3-word-limit
  1007. (length format:cardinal-thousand-block-list)))
  1008. (let loop ((n n)
  1009. (power3 0)
  1010. (s '()))
  1011. (if (= n 0)
  1012. (list->string s)
  1013. (let ((n-before-block (quotient n 1000))
  1014. (n-after-block (remainder n 1000)))
  1015. (loop n-before-block
  1016. (+ power3 1)
  1017. (if (> n-after-block 0)
  1018. (append
  1019. (if (> n-before-block 0)
  1020. (string->list ", ") '())
  1021. (format:num->cardinal999 n-after-block)
  1022. (if (< power3 power3-word-limit)
  1023. (string->list
  1024. (list-ref
  1025. format:cardinal-thousand-block-list
  1026. power3))
  1027. (append
  1028. (string->list " times ten to the ")
  1029. (string->list
  1030. (format:num->ordinal
  1031. (* power3 3)))
  1032. (string->list " power")))
  1033. s)
  1034. s))))))))))
  1035. (format:ordinal-ones-list
  1036. '(#f "first" "second" "third" "fourth" "fifth"
  1037. "sixth" "seventh" "eighth" "ninth" "tenth" "eleventh" "twelfth"
  1038. "thirteenth" "fourteenth" "fifteenth" "sixteenth" "seventeenth"
  1039. "eighteenth" "nineteenth"))
  1040. (format:ordinal-tens-list
  1041. '(#f #f "twentieth" "thirtieth" "fortieth" "fiftieth" "sixtieth"
  1042. "seventieth" "eightieth" "ninetieth"))
  1043. (format:num->ordinal
  1044. (lambda (n)
  1045. (cond ((not (integer? n))
  1046. (format:error
  1047. "only integers can be converted to English ordinals"))
  1048. ((= n 0) "zeroth")
  1049. ((< n 0) (string-append "minus " (format:num->ordinal (- n))))
  1050. (else
  1051. (let ((hundreds (quotient n 100))
  1052. (tens+ones (remainder n 100)))
  1053. (string-append
  1054. (if (> hundreds 0)
  1055. (string-append
  1056. (format:num->cardinal (* hundreds 100))
  1057. (if (= tens+ones 0) "th" " "))
  1058. "")
  1059. (if (= tens+ones 0) ""
  1060. (if (< tens+ones 20)
  1061. (list-ref format:ordinal-ones-list tens+ones)
  1062. (let ((tens (quotient tens+ones 10))
  1063. (ones (remainder tens+ones 10)))
  1064. (if (= ones 0)
  1065. (list-ref format:ordinal-tens-list tens)
  1066. (string-append
  1067. (list-ref format:cardinal-tens-list tens)
  1068. "-"
  1069. (list-ref format:ordinal-ones-list ones))))
  1070. ))))))))
  1071. ;; format inf and nan.
  1072. (format:out-inf-nan
  1073. (lambda (number width digits edigits overch padch)
  1074. ;; inf and nan are always printed exactly as "+inf.0", "-inf.0" or
  1075. ;; "+nan.0", suitably justified in their field. We insist on
  1076. ;; printing this exact form so that the numbers can be read back in.
  1077. (let* ((str (number->string number))
  1078. (len (string-length str))
  1079. (dot (string-index str #\.))
  1080. (digits (+ (or digits 0)
  1081. (if edigits (+ edigits 2) 0))))
  1082. (if (and width overch (< width len))
  1083. (format:out-fill width (integer->char overch))
  1084. (let* ((leftpad (if width
  1085. (max (- width (max len (+ dot 1 digits))) 0)
  1086. 0))
  1087. (rightpad (if width
  1088. (max (- width leftpad len) 0)
  1089. 0))
  1090. (padch (integer->char (or padch format:space-ch))))
  1091. (format:out-fill leftpad padch)
  1092. (format:out-str str)
  1093. (format:out-fill rightpad padch))))))
  1094. ;; format fixed flonums (~F)
  1095. (format:out-fixed
  1096. (lambda (modifier number pars)
  1097. (if (not (or (number? number) (string? number)))
  1098. (format:error "argument is not a number or a number string"))
  1099. (let ((l (length pars)))
  1100. (let ((width (format:par pars l 0 #f "width"))
  1101. (digits (format:par pars l 1 #f "digits"))
  1102. (scale (format:par pars l 2 0 #f))
  1103. (overch (format:par pars l 3 #f #f))
  1104. (padch (format:par pars l 4 format:space-ch #f)))
  1105. (cond
  1106. ((or (inf? number) (nan? number))
  1107. (format:out-inf-nan number width digits #f overch padch))
  1108. (digits
  1109. (format:parse-float
  1110. (if (string? number) number (number->string number)) #t scale)
  1111. (if (<= (- format:fn-len format:fn-dot) digits)
  1112. (format:fn-zfill #f (- digits (- format:fn-len format:fn-dot)))
  1113. (format:fn-round digits))
  1114. (if width
  1115. (let ((numlen (+ format:fn-len 1)))
  1116. (if (or (not format:fn-pos?) (eq? modifier 'at))
  1117. (set! numlen (+ numlen 1)))
  1118. (if (and (= format:fn-dot 0) (> width (+ digits 1)))
  1119. (set! numlen (+ numlen 1)))
  1120. (if (< numlen width)
  1121. (format:out-fill (- width numlen) (integer->char padch)))
  1122. (if (and overch (> numlen width))
  1123. (format:out-fill width (integer->char overch))
  1124. (format:fn-out modifier (> width (+ digits 1)))))
  1125. (format:fn-out modifier #t)))
  1126. (else
  1127. (format:parse-float
  1128. (if (string? number) number (number->string number)) #t scale)
  1129. (format:fn-strip)
  1130. (if width
  1131. (let ((numlen (+ format:fn-len 1)))
  1132. (if (or (not format:fn-pos?) (eq? modifier 'at))
  1133. (set! numlen (+ numlen 1)))
  1134. (if (= format:fn-dot 0)
  1135. (set! numlen (+ numlen 1)))
  1136. (if (< numlen width)
  1137. (format:out-fill (- width numlen) (integer->char padch)))
  1138. (if (> numlen width) ; adjust precision if possible
  1139. (let ((dot-index (- numlen
  1140. (- format:fn-len format:fn-dot))))
  1141. (if (> dot-index width)
  1142. (if overch ; numstr too big for required width
  1143. (format:out-fill width (integer->char overch))
  1144. (format:fn-out modifier #t))
  1145. (begin
  1146. (format:fn-round (- width dot-index))
  1147. (format:fn-out modifier #t))))
  1148. (format:fn-out modifier #t)))
  1149. (format:fn-out modifier #t))))))))
  1150. ;; format exponential flonums (~E)
  1151. (format:out-expon
  1152. (lambda (modifier number pars)
  1153. (if (not (or (number? number) (string? number)))
  1154. (format:error "argument is not a number"))
  1155. (let ((l (length pars)))
  1156. (let ((width (format:par pars l 0 #f "width"))
  1157. (digits (format:par pars l 1 #f "digits"))
  1158. (edigits (format:par pars l 2 #f "exponent digits"))
  1159. (scale (format:par pars l 3 1 #f))
  1160. (overch (format:par pars l 4 #f #f))
  1161. (padch (format:par pars l 5 format:space-ch #f))
  1162. (expch (format:par pars l 6 #f #f)))
  1163. (cond
  1164. ((or (inf? number) (nan? number))
  1165. (format:out-inf-nan number width digits edigits overch padch))
  1166. (digits ; fixed precision
  1167. (let ((digits (if (> scale 0)
  1168. (if (< scale (+ digits 2))
  1169. (+ (- digits scale) 1)
  1170. 0)
  1171. digits)))
  1172. (format:parse-float
  1173. (if (string? number) number (number->string number)) #f scale)
  1174. (if (<= (- format:fn-len format:fn-dot) digits)
  1175. (format:fn-zfill #f (- digits (- format:fn-len format:fn-dot)))
  1176. (format:fn-round digits))
  1177. (if width
  1178. (if (and edigits overch (> format:en-len edigits))
  1179. (format:out-fill width (integer->char overch))
  1180. (let ((numlen (+ format:fn-len 3))) ; .E+
  1181. (if (or (not format:fn-pos?) (eq? modifier 'at))
  1182. (set! numlen (+ numlen 1)))
  1183. (if (and (= format:fn-dot 0) (> width (+ digits 1)))
  1184. (set! numlen (+ numlen 1)))
  1185. (set! numlen
  1186. (+ numlen
  1187. (if (and edigits (>= edigits format:en-len))
  1188. edigits
  1189. format:en-len)))
  1190. (if (< numlen width)
  1191. (format:out-fill (- width numlen)
  1192. (integer->char padch)))
  1193. (if (and overch (> numlen width))
  1194. (format:out-fill width (integer->char overch))
  1195. (begin
  1196. (format:fn-out modifier (> width (- numlen 1)))
  1197. (format:en-out edigits expch)))))
  1198. (begin
  1199. (format:fn-out modifier #t)
  1200. (format:en-out edigits expch)))))
  1201. (else
  1202. (format:parse-float
  1203. (if (string? number) number (number->string number)) #f scale)
  1204. (format:fn-strip)
  1205. (if width
  1206. (if (and edigits overch (> format:en-len edigits))
  1207. (format:out-fill width (integer->char overch))
  1208. (let ((numlen (+ format:fn-len 3))) ; .E+
  1209. (if (or (not format:fn-pos?) (eq? modifier 'at))
  1210. (set! numlen (+ numlen 1)))
  1211. (if (= format:fn-dot 0)
  1212. (set! numlen (+ numlen 1)))
  1213. (set! numlen
  1214. (+ numlen
  1215. (if (and edigits (>= edigits format:en-len))
  1216. edigits
  1217. format:en-len)))
  1218. (if (< numlen width)
  1219. (format:out-fill (- width numlen)
  1220. (integer->char padch)))
  1221. (if (> numlen width) ; adjust precision if possible
  1222. (let ((f (- format:fn-len format:fn-dot))) ; fract len
  1223. (if (> (- numlen f) width)
  1224. (if overch ; numstr too big for required width
  1225. (format:out-fill width
  1226. (integer->char overch))
  1227. (begin
  1228. (format:fn-out modifier #t)
  1229. (format:en-out edigits expch)))
  1230. (begin
  1231. (format:fn-round (+ (- f numlen) width))
  1232. (format:fn-out modifier #t)
  1233. (format:en-out edigits expch))))
  1234. (begin
  1235. (format:fn-out modifier #t)
  1236. (format:en-out edigits expch)))))
  1237. (begin
  1238. (format:fn-out modifier #t)
  1239. (format:en-out edigits expch)))))))))
  1240. ;; format general flonums (~G)
  1241. (format:out-general
  1242. (lambda (modifier number pars)
  1243. (if (not (or (number? number) (string? number)))
  1244. (format:error "argument is not a number or a number string"))
  1245. (let ((l (length pars)))
  1246. (let ((width (if (> l 0) (list-ref pars 0) #f))
  1247. (digits (if (> l 1) (list-ref pars 1) #f))
  1248. (edigits (if (> l 2) (list-ref pars 2) #f))
  1249. (overch (if (> l 4) (list-ref pars 4) #f))
  1250. (padch (if (> l 5) (list-ref pars 5) #f)))
  1251. (cond
  1252. ((or (inf? number) (nan? number))
  1253. ;; FIXME: this isn't right.
  1254. (format:out-inf-nan number width digits edigits overch padch))
  1255. (else
  1256. (format:parse-float
  1257. (if (string? number) number (number->string number)) #t 0)
  1258. (format:fn-strip)
  1259. (let* ((ee (if edigits (+ edigits 2) 4)) ; for the following algorithm
  1260. (ww (if width (- width ee) #f)) ; see Steele's CL book p.395
  1261. (n (if (= format:fn-dot 0) ; number less than (abs 1.0) ?
  1262. (- (format:fn-zlead))
  1263. format:fn-dot))
  1264. (d (if digits
  1265. digits
  1266. (max format:fn-len (min n 7)))) ; q = format:fn-len
  1267. (dd (- d n)))
  1268. (if (<= 0 dd d)
  1269. (begin
  1270. (format:out-fixed modifier number (list ww dd #f overch padch))
  1271. (format:out-fill ee #\space)) ;~@T not implemented yet
  1272. (format:out-expon modifier number pars)))))))))
  1273. ;; format dollar flonums (~$)
  1274. (format:out-dollar
  1275. (lambda (modifier number pars)
  1276. (if (not (or (number? number) (string? number)))
  1277. (format:error "argument is not a number or a number string"))
  1278. (let ((l (length pars)))
  1279. (let ((digits (format:par pars l 0 2 "digits"))
  1280. (mindig (format:par pars l 1 1 "mindig"))
  1281. (width (format:par pars l 2 0 "width"))
  1282. (padch (format:par pars l 3 format:space-ch #f)))
  1283. (cond
  1284. ((or (inf? number) (nan? number))
  1285. (format:out-inf-nan number width digits #f #f padch))
  1286. (else
  1287. (format:parse-float
  1288. (if (string? number) number (number->string number)) #t 0)
  1289. (if (<= (- format:fn-len format:fn-dot) digits)
  1290. (format:fn-zfill #f (- digits (- format:fn-len format:fn-dot)))
  1291. (format:fn-round digits))
  1292. (let ((numlen (+ format:fn-len 1)))
  1293. (if (or (not format:fn-pos?) (memq modifier '(at colon-at)))
  1294. (set! numlen (+ numlen 1)))
  1295. (if (and mindig (> mindig format:fn-dot))
  1296. (set! numlen (+ numlen (- mindig format:fn-dot))))
  1297. (if (and (= format:fn-dot 0) (not mindig))
  1298. (set! numlen (+ numlen 1)))
  1299. (if (< numlen width)
  1300. (case modifier
  1301. ((colon)
  1302. (if (not format:fn-pos?)
  1303. (format:out-char #\-))
  1304. (format:out-fill (- width numlen) (integer->char padch)))
  1305. ((at)
  1306. (format:out-fill (- width numlen) (integer->char padch))
  1307. (format:out-char (if format:fn-pos? #\+ #\-)))
  1308. ((colon-at)
  1309. (format:out-char (if format:fn-pos? #\+ #\-))
  1310. (format:out-fill (- width numlen) (integer->char padch)))
  1311. (else
  1312. (format:out-fill (- width numlen) (integer->char padch))
  1313. (if (not format:fn-pos?)
  1314. (format:out-char #\-))))
  1315. (if format:fn-pos?
  1316. (if (memq modifier '(at colon-at)) (format:out-char #\+))
  1317. (format:out-char #\-))))
  1318. (if (and mindig (> mindig format:fn-dot))
  1319. (format:out-fill (- mindig format:fn-dot) #\0))
  1320. (if (and (= format:fn-dot 0) (not mindig))
  1321. (format:out-char #\0))
  1322. (format:out-substr format:fn-str 0 format:fn-dot)
  1323. (format:out-char #\.)
  1324. (format:out-substr format:fn-str format:fn-dot format:fn-len)))))))
  1325. ; the flonum buffers
  1326. (format:fn-max 400) ; max. number of number digits
  1327. (format:fn-str #f) ; number buffer
  1328. (format:fn-len 0) ; digit length of number
  1329. (format:fn-dot #f) ; dot position of number
  1330. (format:fn-pos? #t) ; number positive?
  1331. (format:en-max 10) ; max. number of exponent digits
  1332. (format:en-str #f) ; exponent buffer
  1333. (format:en-len 0) ; digit length of exponent
  1334. (format:en-pos? #t) ; exponent positive?
  1335. (format:parse-float
  1336. (lambda (num-str fixed? scale)
  1337. (set! format:fn-pos? #t)
  1338. (set! format:fn-len 0)
  1339. (set! format:fn-dot #f)
  1340. (set! format:en-pos? #t)
  1341. (set! format:en-len 0)
  1342. (do ((i 0 (+ i 1))
  1343. (left-zeros 0)
  1344. (mantissa? #t)
  1345. (all-zeros? #t)
  1346. (num-len (string-length num-str))
  1347. (c #f)) ; current exam. character in num-str
  1348. ((= i num-len)
  1349. (if (not format:fn-dot)
  1350. (set! format:fn-dot format:fn-len))
  1351. (if all-zeros?
  1352. (begin
  1353. (set! left-zeros 0)
  1354. (set! format:fn-dot 0)
  1355. (set! format:fn-len 1)))
  1356. ;; now format the parsed values according to format's need
  1357. (if fixed?
  1358. (begin ; fixed format m.nnn or .nnn
  1359. (if (and (> left-zeros 0) (> format:fn-dot 0))
  1360. (if (> format:fn-dot left-zeros)
  1361. (begin ; norm 0{0}nn.mm to nn.mm
  1362. (format:fn-shiftleft left-zeros)
  1363. (set! format:fn-dot (- format:fn-dot left-zeros))
  1364. (set! left-zeros 0))
  1365. (begin ; normalize 0{0}.nnn to .nnn
  1366. (format:fn-shiftleft format:fn-dot)
  1367. (set! left-zeros (- left-zeros format:fn-dot))
  1368. (set! format:fn-dot 0))))
  1369. (if (or (not (= scale 0)) (> format:en-len 0))
  1370. (let ((shift (+ scale (format:en-int))))
  1371. (cond
  1372. (all-zeros? #t)
  1373. ((> (+ format:fn-dot shift) format:fn-len)
  1374. (format:fn-zfill
  1375. #f (- shift (- format:fn-len format:fn-dot)))
  1376. (set! format:fn-dot format:fn-len))
  1377. ((< (+ format:fn-dot shift) 0)
  1378. (format:fn-zfill #t (- (- shift) format:fn-dot))
  1379. (set! format:fn-dot 0))
  1380. (else
  1381. (if (> left-zeros 0)
  1382. (if (<= left-zeros shift) ; shift always > 0 here
  1383. (format:fn-shiftleft shift) ; shift out 0s
  1384. (begin
  1385. (format:fn-shiftleft left-zeros)
  1386. (set! format:fn-dot (- shift left-zeros))))
  1387. (set! format:fn-dot (+ format:fn-dot shift))))))))
  1388. (let ((negexp ; expon format m.nnnEee
  1389. (if (> left-zeros 0)
  1390. (- left-zeros format:fn-dot -1)
  1391. (if (= format:fn-dot 0) 1 0))))
  1392. (if (> left-zeros 0)
  1393. (begin ; normalize 0{0}.nnn to n.nn
  1394. (format:fn-shiftleft left-zeros)
  1395. (set! format:fn-dot 1))
  1396. (if (= format:fn-dot 0)
  1397. (set! format:fn-dot 1)))
  1398. (format:en-set (- (+ (- format:fn-dot scale) (format:en-int))
  1399. negexp))
  1400. (cond
  1401. (all-zeros?
  1402. (format:en-set 0)
  1403. (set! format:fn-dot 1))
  1404. ((< scale 0) ; leading zero
  1405. (format:fn-zfill #t (- scale))
  1406. (set! format:fn-dot 0))
  1407. ((> scale format:fn-dot)
  1408. (format:fn-zfill #f (- scale format:fn-dot))
  1409. (set! format:fn-dot scale))
  1410. (else
  1411. (set! format:fn-dot scale)))))
  1412. #t)
  1413. ;; do body
  1414. (set! c (string-ref num-str i)) ; parse the output of number->string
  1415. (cond ; which can be any valid number
  1416. ((char-numeric? c) ; representation of R4RS except
  1417. (if mantissa? ; complex numbers
  1418. (begin
  1419. (if (char=? c #\0)
  1420. (if all-zeros?
  1421. (set! left-zeros (+ left-zeros 1)))
  1422. (begin
  1423. (set! all-zeros? #f)))
  1424. (string-set! format:fn-str format:fn-len c)
  1425. (set! format:fn-len (+ format:fn-len 1)))
  1426. (begin
  1427. (string-set! format:en-str format:en-len c)
  1428. (set! format:en-len (+ format:en-len 1)))))
  1429. ((or (char=? c #\-) (char=? c #\+))
  1430. (if mantissa?
  1431. (set! format:fn-pos? (char=? c #\+))
  1432. (set! format:en-pos? (char=? c #\+))))
  1433. ((char=? c #\.)
  1434. (set! format:fn-dot format:fn-len))
  1435. ((char=? c #\e)
  1436. (set! mantissa? #f))
  1437. ((char=? c #\E)
  1438. (set! mantissa? #f))
  1439. ((char-whitespace? c) #t)
  1440. ((char=? c #\d) #t) ; decimal radix prefix
  1441. ((char=? c #\#) #t)
  1442. (else
  1443. (format:error "illegal character `~c' in number->string" c))))))
  1444. (format:en-int
  1445. (lambda () ; convert exponent string to integer
  1446. (if (= format:en-len 0)
  1447. 0
  1448. (do ((i 0 (+ i 1))
  1449. (n 0))
  1450. ((= i format:en-len)
  1451. (if format:en-pos?
  1452. n
  1453. (- n)))
  1454. (set! n (+ (* n 10) (- (char->integer (string-ref format:en-str i))
  1455. format:zero-ch)))))))
  1456. (format:en-set ; set exponent string number
  1457. (lambda (en)
  1458. (set! format:en-len 0)
  1459. (set! format:en-pos? (>= en 0))
  1460. (let ((en-str (number->string en)))
  1461. (do ((i 0 (+ i 1))
  1462. (en-len (string-length en-str))
  1463. (c #f))
  1464. ((= i en-len))
  1465. (set! c (string-ref en-str i))
  1466. (if (char-numeric? c)
  1467. (begin
  1468. (string-set! format:en-str format:en-len c)
  1469. (set! format:en-len (+ format:en-len 1))))))))
  1470. (format:fn-zfill ; fill current number string with 0s
  1471. (lambda (left? n)
  1472. (if (> (+ n format:fn-len) format:fn-max) ; from the left or right
  1473. (format:error "number is too long to format (enlarge format:fn-max)"))
  1474. (set! format:fn-len (+ format:fn-len n))
  1475. (if left?
  1476. (do ((i format:fn-len (- i 1))) ; fill n 0s to left
  1477. ((< i 0))
  1478. (string-set! format:fn-str i
  1479. (if (< i n)
  1480. #\0
  1481. (string-ref format:fn-str (- i n)))))
  1482. (do ((i (- format:fn-len n) (+ i 1))) ; fill n 0s to the right
  1483. ((= i format:fn-len))
  1484. (string-set! format:fn-str i #\0)))))
  1485. (format:fn-shiftleft ; shift left current number n positions
  1486. (lambda (n)
  1487. (if (> n format:fn-len)
  1488. (format:error "internal error in format:fn-shiftleft (~d,~d)"
  1489. n format:fn-len))
  1490. (do ((i n (+ i 1)))
  1491. ((= i format:fn-len)
  1492. (set! format:fn-len (- format:fn-len n)))
  1493. (string-set! format:fn-str (- i n) (string-ref format:fn-str i)))))
  1494. (format:fn-round ; round format:fn-str
  1495. (lambda (digits)
  1496. (set! digits (+ digits format:fn-dot))
  1497. (do ((i digits (- i 1)) ; "099",2 -> "10"
  1498. (c 5)) ; "023",2 -> "02"
  1499. ((or (= c 0) (< i 0)) ; "999",2 -> "100"
  1500. (if (= c 1) ; "005",2 -> "01"
  1501. (begin ; carry overflow
  1502. (set! format:fn-len digits)
  1503. (format:fn-zfill #t 1) ; add a 1 before fn-str
  1504. (string-set! format:fn-str 0 #\1)
  1505. (set! format:fn-dot (+ format:fn-dot 1)))
  1506. (set! format:fn-len digits)))
  1507. (set! c (+ (- (char->integer (string-ref format:fn-str i))
  1508. format:zero-ch) c))
  1509. (string-set! format:fn-str i (integer->char
  1510. (if (< c 10)
  1511. (+ c format:zero-ch)
  1512. (+ (- c 10) format:zero-ch))))
  1513. (set! c (if (< c 10) 0 1)))))
  1514. (format:fn-out
  1515. (lambda (modifier add-leading-zero?)
  1516. (if format:fn-pos?
  1517. (if (eq? modifier 'at)
  1518. (format:out-char #\+))
  1519. (format:out-char #\-))
  1520. (if (= format:fn-dot 0)
  1521. (if add-leading-zero?
  1522. (format:out-char #\0))
  1523. (format:out-substr format:fn-str 0 format:fn-dot))
  1524. (format:out-char #\.)
  1525. (format:out-substr format:fn-str format:fn-dot format:fn-len)))
  1526. (format:en-out
  1527. (lambda (edigits expch)
  1528. (format:out-char (if expch (integer->char expch) format:expch))
  1529. (format:out-char (if format:en-pos? #\+ #\-))
  1530. (if edigits
  1531. (if (< format:en-len edigits)
  1532. (format:out-fill (- edigits format:en-len) #\0)))
  1533. (format:out-substr format:en-str 0 format:en-len)))
  1534. (format:fn-strip ; strip trailing zeros but one
  1535. (lambda ()
  1536. (string-set! format:fn-str format:fn-len #\0)
  1537. (do ((i format:fn-len (- i 1)))
  1538. ((or (not (char=? (string-ref format:fn-str i) #\0))
  1539. (<= i format:fn-dot))
  1540. (set! format:fn-len (+ i 1))))))
  1541. (format:fn-zlead ; count leading zeros
  1542. (lambda ()
  1543. (do ((i 0 (+ i 1)))
  1544. ((or (= i format:fn-len)
  1545. (not (char=? (string-ref format:fn-str i) #\0)))
  1546. (if (= i format:fn-len) ; found a real zero
  1547. 0
  1548. i)))))
  1549. ;;; some global functions not found in SLIB
  1550. (string-capitalize-first ; "hello" -> "Hello"
  1551. (lambda (str)
  1552. (let ((cap-str (string-copy str)) ; "hELLO" -> "Hello"
  1553. (non-first-alpha #f) ; "*hello" -> "*Hello"
  1554. (str-len (string-length str))) ; "hello you" -> "Hello you"
  1555. (do ((i 0 (+ i 1)))
  1556. ((= i str-len) cap-str)
  1557. (let ((c (string-ref str i)))
  1558. (if (char-alphabetic? c)
  1559. (if non-first-alpha
  1560. (string-set! cap-str i (char-downcase c))
  1561. (begin
  1562. (set! non-first-alpha #t)
  1563. (string-set! cap-str i (char-upcase c))))))))))
  1564. ;; Aborts the program when a formatting error occures. This is a null
  1565. ;; argument closure to jump to the interpreters toplevel continuation.
  1566. (format:abort (lambda () (error "error in format"))))
  1567. (set! format:error-save format:error)
  1568. (set! format:fn-str (make-string format:fn-max)) ; number buffer
  1569. (set! format:en-str (make-string format:en-max)) ; exponent buffer
  1570. (apply format:format args)))
  1571. ;; Thanks to Shuji Narazaki
  1572. (module-set! the-root-module 'format format)