aboutsummaryrefslogtreecommitdiff
path: root/sys/fmtio/dtoc.x
blob: 6bf7571e1ff23fafd68336af9d7cc2d93bf805bd (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.

include	<ctype.h>
include	<printf.h>

# DTOC -- Format and output a floating point number, in any of the formats
# F,E,G,H, or M (H and M are hours-minutes-seconds and minutes-seconds formats,
# respectively).

int procedure dtoc (dval, outstr, maxch, decpl, a_fmt, width)

double	dval			# number to be output
char	outstr[ARB]		# output string
int	maxch			# size of the output string
int	decpl			# number of decimal places or precision
int	a_fmt, fmt		# format type (feghm)
int	width			# field width

bool	neg
double	val
int	op, round, h, m, s, f, v, i
int	dtoc3(), ltoc()

define	output {outstr[op]=$1;op=op+1;if(op>maxch)goto retry_}
define	retry_ 91

begin
	# If HMS format is not desired, simply call DTOC3.  Control also
	# returns to this point in the event of overflow.

	fmt = a_fmt
	if (IS_UPPER (fmt))
	    fmt = TO_LOWER (fmt)

	if (fmt == FMT_FIXED || fmt == FMT_EXPON || fmt == FMT_GENERAL ||
	    IS_INDEFD(dval)) {
retry_	
	    return (dtoc3 (dval, outstr, maxch, decpl, fmt, width))
	}

	# HMS format is implemented using calls to DTOC3, LTOC.  Use zero
	# fill to get two chars for the second and third fields, if necessary.
	# The second field is omitted for "m" format.  No whitespace is
	# permitted in an HMS (or other) number.  If the format is %H or %M
	# (instead of the usual %h or %m) scale the number by 15 before output
	# (converting degrees to hours).

	if (IS_UPPER (a_fmt))
	    val = dval / 15.0
	else
	    val = dval

	# Working with a positive number simplifies things.
	neg = (val < 0.0)
	if (neg)
	    val = -val

	# Decompose number into HMS or MS.
	h = 0
	if (fmt == FMT_HMS) {
	    h = int(val);  val = (val - h) * 60.0
	}
	m = int(val);  val = (val - m) * 60.0
	s = int(val);  val = (val - s)

	# Round the fractional seconds field and carry if the rounded value
	# is greater than 60.  This has to be done explicitly due to the
	# "base 60" sexagesimal arithmetic.

	round = (10.0 ** decpl)
	f = int (val * round + 0.5)
	while (f >= round) {
	    f = f - round
	    s = s + 1
	}
	while (s >= 60) {
	    s = s - 60
	    m = m + 1
	}
	while (m >= 60) {
	    m = m - 60
	    h = h + 1
	}

	# Format the output string.
	op = 1
	if (neg)
	    output ('-')

	# Output the first field, which is the hours field for HMS format,
	# or the minutes field for MS format.

	if (fmt == FMT_HMS)
	    v = h
	else
	    v = h * 60 + m
	op = op + ltoc (v, outstr[op], maxch-op+1)
	output (':')

	# Output the minutes field in HMS format.
	if (fmt == FMT_HMS) {
	    output (TO_DIGIT (m / 10))
	    output (TO_DIGIT (mod (m, 10)))
	    output (':')
	}

	# Output the seconds field.
	output (TO_DIGIT (s / 10))
	output (TO_DIGIT (mod (s, 10)))

	# Output the fraction, if any.
	if (decpl > 0) {
	    output ('.')
	    do i = 1, decpl {
		round = round / 10
		output (TO_DIGIT (f / round))
		f = mod (f, round)
	    }
	}

	# If the HMS format does not fit, go try a more compact format.
	if (op-1 > abs(width) || op > maxch) {
	    fmt = FMT_GENERAL
	    goto retry_
	}

	outstr[op] = EOS
	return (op-1)
end