format.scm 73 KB

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