format.scm 57 KB

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