22 |
#include "error.h" |
#include "error.h" |
23 |
#include <ctype.h> |
#include <ctype.h> |
24 |
#include <errno.h> |
#include <errno.h> |
25 |
|
#include <fcntl.h> |
26 |
#include <float.h> |
#include <float.h> |
27 |
#include <math.h> |
#include <math.h> |
28 |
#include <stdio.h> |
#include <stdio.h> |
29 |
#include <stdlib.h> |
#include <stdlib.h> |
30 |
|
#include <sys/stat.h> |
31 |
#include <time.h> |
#include <time.h> |
32 |
|
#include <unistd.h> |
33 |
#include "alloc.h" |
#include "alloc.h" |
34 |
#include "case.h" |
#include "case.h" |
35 |
#include "dictionary.h" |
#include "dictionary.h" |
38 |
#include "hash.h" |
#include "hash.h" |
39 |
#include "magic.h" |
#include "magic.h" |
40 |
#include "misc.h" |
#include "misc.h" |
41 |
|
#include "stat-macros.h" |
42 |
#include "str.h" |
#include "str.h" |
43 |
#include "value-labels.h" |
#include "value-labels.h" |
44 |
#include "var.h" |
#include "var.h" |
59 |
|
|
60 |
size_t var_cnt; /* Number of variables. */ |
size_t var_cnt; /* Number of variables. */ |
61 |
struct pfm_var *vars; /* Variables. */ |
struct pfm_var *vars; /* Variables. */ |
62 |
|
|
63 |
|
int digits; /* Digits of precision. */ |
64 |
}; |
}; |
65 |
|
|
66 |
/* A variable to write to the portable file. */ |
/* A variable to write to the portable file. */ |
79 |
static void format_trig_double (long double, int base_10_precision, char[]); |
static void format_trig_double (long double, int base_10_precision, char[]); |
80 |
static char *format_trig_int (int, bool force_sign, char[]); |
static char *format_trig_int (int, bool force_sign, char[]); |
81 |
|
|
82 |
/* Writes the dictionary DICT to portable file HANDLE. Returns |
/* Returns default options for writing a portable file. */ |
83 |
nonzero only if successful. DICT will not be modified, except |
struct pfm_write_options |
84 |
to assign short names. */ |
pfm_writer_default_options (void) |
85 |
|
{ |
86 |
|
struct pfm_write_options opts; |
87 |
|
opts.create_writeable = true; |
88 |
|
opts.type = PFM_COMM; |
89 |
|
opts.digits = DBL_DIG; |
90 |
|
return opts; |
91 |
|
} |
92 |
|
|
93 |
|
/* Writes the dictionary DICT to portable file HANDLE according |
94 |
|
to the given OPTS. Returns nonzero only if successful. DICT |
95 |
|
will not be modified, except to assign short names. */ |
96 |
struct pfm_writer * |
struct pfm_writer * |
97 |
pfm_open_writer (struct file_handle *fh, struct dictionary *dict) |
pfm_open_writer (struct file_handle *fh, struct dictionary *dict, |
98 |
|
struct pfm_write_options opts) |
99 |
{ |
{ |
100 |
struct pfm_writer *w = NULL; |
struct pfm_writer *w = NULL; |
101 |
|
mode_t mode; |
102 |
|
int fd; |
103 |
size_t i; |
size_t i; |
104 |
|
|
105 |
|
/* Create file. */ |
106 |
|
mode = S_IRUSR | S_IRGRP | S_IROTH; |
107 |
|
if (opts.create_writeable) |
108 |
|
mode |= S_IWUSR | S_IWGRP | S_IWOTH; |
109 |
|
fd = open (handle_get_filename (fh), O_WRONLY | O_CREAT | O_TRUNC, mode); |
110 |
|
if (fd < 0) |
111 |
|
goto open_error; |
112 |
|
|
113 |
|
/* Open file handle. */ |
114 |
if (!fh_open (fh, "portable file", "we")) |
if (!fh_open (fh, "portable file", "we")) |
115 |
goto error; |
goto error; |
116 |
|
|
117 |
/* Open the physical disk file. */ |
/* Initialize data structures. */ |
118 |
w = xmalloc (sizeof *w); |
w = xmalloc (sizeof *w); |
119 |
w->fh = fh; |
w->fh = fh; |
120 |
w->file = fopen (handle_get_filename (fh), "wb"); |
w->file = fdopen (fd, "w"); |
121 |
|
if (w->file == NULL) |
122 |
|
{ |
123 |
|
close (fd); |
124 |
|
goto open_error; |
125 |
|
} |
126 |
|
|
127 |
w->lc = 0; |
w->lc = 0; |
128 |
w->var_cnt = 0; |
w->var_cnt = 0; |
129 |
w->vars = NULL; |
w->vars = NULL; |
130 |
|
|
|
/* Check that file create succeeded. */ |
|
|
if (w->file == NULL) |
|
|
{ |
|
|
msg (ME, _("An error occurred while opening \"%s\" for writing " |
|
|
"as a portable file: %s."), |
|
|
handle_get_filename (fh), strerror (errno)); |
|
|
err_cond_fail (); |
|
|
goto error; |
|
|
} |
|
|
|
|
131 |
w->var_cnt = dict_get_var_cnt (dict); |
w->var_cnt = dict_get_var_cnt (dict); |
132 |
w->vars = xmalloc (sizeof *w->vars * w->var_cnt); |
w->vars = xmalloc (sizeof *w->vars * w->var_cnt); |
133 |
for (i = 0; i < w->var_cnt; i++) |
for (i = 0; i < w->var_cnt; i++) |
138 |
pv->fv = dv->fv; |
pv->fv = dv->fv; |
139 |
} |
} |
140 |
|
|
141 |
|
w->digits = opts.digits; |
142 |
|
if (w->digits < 1) |
143 |
|
{ |
144 |
|
msg (ME, _("Invalid decimal digits count %d. Treating as %d."), |
145 |
|
w->digits, DBL_DIG); |
146 |
|
w->digits = DBL_DIG; |
147 |
|
} |
148 |
|
|
149 |
/* Write file header. */ |
/* Write file header. */ |
150 |
if (!write_header (w) |
if (!write_header (w) |
151 |
|| !write_version_data (w) |
|| !write_version_data (w) |
156 |
|
|
157 |
return w; |
return w; |
158 |
|
|
159 |
error: |
error: |
160 |
pfm_close_writer (w); |
pfm_close_writer (w); |
161 |
return NULL; |
return NULL; |
162 |
|
|
163 |
|
open_error: |
164 |
|
msg (ME, _("An error occurred while opening \"%s\" for writing " |
165 |
|
"as a portable file: %s."), |
166 |
|
handle_get_filename (fh), strerror (errno)); |
167 |
|
err_cond_fail (); |
168 |
|
goto error; |
169 |
} |
} |
170 |
|
|
171 |
/* Write NBYTES starting at BUF to the portable file represented by |
/* Write NBYTES starting at BUF to the portable file represented by |
209 |
write_float (struct pfm_writer *w, double d) |
write_float (struct pfm_writer *w, double d) |
210 |
{ |
{ |
211 |
char buffer[64]; |
char buffer[64]; |
212 |
format_trig_double (d, DBL_DIG, buffer); |
format_trig_double (d, floor (d) == d ? DBL_DIG : w->digits, buffer); |
213 |
return buf_write (w, buffer, strlen (buffer)) && buf_write (w, "/", 1); |
return buf_write (w, buffer, strlen (buffer)) && buf_write (w, "/", 1); |
214 |
} |
} |
215 |
|
|
794 |
required base-30 precision as 2/3 of the base-10 precision |
required base-30 precision as 2/3 of the base-10 precision |
795 |
(log30(10) = .68). */ |
(log30(10) = .68). */ |
796 |
assert (base_10_precision > 0); |
assert (base_10_precision > 0); |
797 |
|
if (base_10_precision > LDBL_DIG) |
798 |
|
base_10_precision = LDBL_DIG; |
799 |
base_30_precision = DIV_RND_UP (base_10_precision * 2, 3); |
base_30_precision = DIV_RND_UP (base_10_precision * 2, 3); |
800 |
if (trig_cnt > base_30_precision) |
if (trig_cnt > base_30_precision) |
801 |
{ |
{ |