format.scm 74 KB

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