format.scm 65 KB

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