1*101e15b5SRichard Lowe /*
2*101e15b5SRichard Lowe * CDDL HEADER START
3*101e15b5SRichard Lowe *
4*101e15b5SRichard Lowe * The contents of this file are subject to the terms of the
5*101e15b5SRichard Lowe * Common Development and Distribution License, Version 1.0 only
6*101e15b5SRichard Lowe * (the "License"). You may not use this file except in compliance
7*101e15b5SRichard Lowe * with the License.
8*101e15b5SRichard Lowe *
9*101e15b5SRichard Lowe * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*101e15b5SRichard Lowe * or http://www.opensolaris.org/os/licensing.
11*101e15b5SRichard Lowe * See the License for the specific language governing permissions
12*101e15b5SRichard Lowe * and limitations under the License.
13*101e15b5SRichard Lowe *
14*101e15b5SRichard Lowe * When distributing Covered Code, include this CDDL HEADER in each
15*101e15b5SRichard Lowe * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*101e15b5SRichard Lowe * If applicable, add the following below this CDDL HEADER, with the
17*101e15b5SRichard Lowe * fields enclosed by brackets "[]" replaced with your own identifying
18*101e15b5SRichard Lowe * information: Portions Copyright [yyyy] [name of copyright owner]
19*101e15b5SRichard Lowe *
20*101e15b5SRichard Lowe * CDDL HEADER END
21*101e15b5SRichard Lowe */
22*101e15b5SRichard Lowe /*
23*101e15b5SRichard Lowe * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24*101e15b5SRichard Lowe * Use is subject to license terms.
25*101e15b5SRichard Lowe */
26*101e15b5SRichard Lowe
27*101e15b5SRichard Lowe #include "utility.h"
28*101e15b5SRichard Lowe
29*101e15b5SRichard Lowe #include "initialize.h"
30*101e15b5SRichard Lowe #include "statistics.h"
31*101e15b5SRichard Lowe #include "streams_common.h"
32*101e15b5SRichard Lowe #include "streams.h"
33*101e15b5SRichard Lowe
34*101e15b5SRichard Lowe /*
35*101e15b5SRichard Lowe * utility
36*101e15b5SRichard Lowe *
37*101e15b5SRichard Lowe * Overview
38*101e15b5SRichard Lowe * utility.c contains the general purpose routines used in various locations
39*101e15b5SRichard Lowe * throughout sort. It provides a number of interfaces that maintain local
40*101e15b5SRichard Lowe * state relevant to this instance of sort. We discuss the more significant
41*101e15b5SRichard Lowe * of these interfaces below.
42*101e15b5SRichard Lowe *
43*101e15b5SRichard Lowe * Output guard
44*101e15b5SRichard Lowe * sort is one of the few Unix utilities that is capable of working "in
45*101e15b5SRichard Lowe * place"; that is, sort can manipulate an input file and place its output in
46*101e15b5SRichard Lowe * a file of the same name safely. This is handled in this implementation by
47*101e15b5SRichard Lowe * the output guard facility. In the case of an interrupt or other fatal
48*101e15b5SRichard Lowe * signal, sort essays to restore the original input file.
49*101e15b5SRichard Lowe *
50*101e15b5SRichard Lowe * Temporary file cleanup
51*101e15b5SRichard Lowe * Similar to the output guard facility, sort cleans up its temporary files in
52*101e15b5SRichard Lowe * the case of interruption (or normal exit, for that matter); this is handled
53*101e15b5SRichard Lowe * by registering a list of file pointers for later use by the atexit handler.
54*101e15b5SRichard Lowe *
55*101e15b5SRichard Lowe * Temporary filename security
56*101e15b5SRichard Lowe * sort protects against "open-through-link" security attacks by verifying
57*101e15b5SRichard Lowe * that the selected temporary file name is unused. If the file name is in
58*101e15b5SRichard Lowe * use, the pattern is readjusted until an available name pattern is
59*101e15b5SRichard Lowe * discovered.
60*101e15b5SRichard Lowe *
61*101e15b5SRichard Lowe * Buffered I/O
62*101e15b5SRichard Lowe * sort has a simple buffered I/O facility of its own, to facilitate writing
63*101e15b5SRichard Lowe * data in large quantities (particularly for multibyte locales). cxwrite()
64*101e15b5SRichard Lowe * is the base routine, while wxwrite(), which handles multibyte buffers, is
65*101e15b5SRichard Lowe * built on top of cxwrite().
66*101e15b5SRichard Lowe */
67*101e15b5SRichard Lowe
68*101e15b5SRichard Lowe #define XBUFFER_SIZE (32 * KILOBYTE)
69*101e15b5SRichard Lowe
70*101e15b5SRichard Lowe #define EXIT_OK 0
71*101e15b5SRichard Lowe #define EXIT_FAILURE 1
72*101e15b5SRichard Lowe #define EXIT_ERROR 2
73*101e15b5SRichard Lowe #define EXIT_INTERNAL 3
74*101e15b5SRichard Lowe
75*101e15b5SRichard Lowe static int held_fd = -1;
76*101e15b5SRichard Lowe
77*101e15b5SRichard Lowe static stream_t **cleanup_chain = NULL;
78*101e15b5SRichard Lowe
79*101e15b5SRichard Lowe static char *output_guard_tempname = NULL;
80*101e15b5SRichard Lowe static ssize_t output_guard_size = 0;
81*101e15b5SRichard Lowe static char *output_guard_filename = NULL;
82*101e15b5SRichard Lowe static int output_guard_copy_complete = 0;
83*101e15b5SRichard Lowe
84*101e15b5SRichard Lowe static const char *default_tmpdir = "/var/tmp";
85*101e15b5SRichard Lowe static const char *default_template = "/stmAAAXXXXXX";
86*101e15b5SRichard Lowe static const char *default_template_count = ".00000000";
87*101e15b5SRichard Lowe static char *current_tmpdir;
88*101e15b5SRichard Lowe static char *current_template;
89*101e15b5SRichard Lowe
90*101e15b5SRichard Lowe static const char PNAME_FMT[] = "%s: ";
91*101e15b5SRichard Lowe static const char ERRNO_FMT[] = ": %s\n";
92*101e15b5SRichard Lowe static const char *pname = "sort";
93*101e15b5SRichard Lowe
94*101e15b5SRichard Lowe void
swap(void ** a,void ** b)95*101e15b5SRichard Lowe swap(void **a, void **b)
96*101e15b5SRichard Lowe {
97*101e15b5SRichard Lowe void *t;
98*101e15b5SRichard Lowe
99*101e15b5SRichard Lowe t = *a;
100*101e15b5SRichard Lowe *a = *b;
101*101e15b5SRichard Lowe *b = t;
102*101e15b5SRichard Lowe
103*101e15b5SRichard Lowe __S(stats_incr_swaps());
104*101e15b5SRichard Lowe }
105*101e15b5SRichard Lowe
106*101e15b5SRichard Lowe /*
107*101e15b5SRichard Lowe * Temporary file name template handling.
108*101e15b5SRichard Lowe */
109*101e15b5SRichard Lowe static void
reset_file_template()110*101e15b5SRichard Lowe reset_file_template()
111*101e15b5SRichard Lowe {
112*101e15b5SRichard Lowe struct stat s;
113*101e15b5SRichard Lowe
114*101e15b5SRichard Lowe do {
115*101e15b5SRichard Lowe (void) strcpy(current_template, current_tmpdir);
116*101e15b5SRichard Lowe (void) strcat(current_template, default_template);
117*101e15b5SRichard Lowe (void) mktemp(current_template);
118*101e15b5SRichard Lowe (void) strcat(current_template, default_template_count);
119*101e15b5SRichard Lowe } while (lstat(current_template, &s) != -1);
120*101e15b5SRichard Lowe }
121*101e15b5SRichard Lowe
122*101e15b5SRichard Lowe int
bump_file_template()123*101e15b5SRichard Lowe bump_file_template()
124*101e15b5SRichard Lowe {
125*101e15b5SRichard Lowe struct stat s;
126*101e15b5SRichard Lowe int n = strlen(current_template);
127*101e15b5SRichard Lowe int i;
128*101e15b5SRichard Lowe
129*101e15b5SRichard Lowe for (i = n - 1; isdigit((uchar_t)current_template[i]); i--) {
130*101e15b5SRichard Lowe current_template[i]++;
131*101e15b5SRichard Lowe if (current_template[i] > '9')
132*101e15b5SRichard Lowe current_template[i] = '0';
133*101e15b5SRichard Lowe else
134*101e15b5SRichard Lowe break;
135*101e15b5SRichard Lowe }
136*101e15b5SRichard Lowe
137*101e15b5SRichard Lowe if (!isdigit((uchar_t)current_template[i])) {
138*101e15b5SRichard Lowe /*
139*101e15b5SRichard Lowe * Template has been exhausted, so reset.
140*101e15b5SRichard Lowe */
141*101e15b5SRichard Lowe reset_file_template();
142*101e15b5SRichard Lowe }
143*101e15b5SRichard Lowe
144*101e15b5SRichard Lowe if (lstat(current_template, &s) == 0) {
145*101e15b5SRichard Lowe /*
146*101e15b5SRichard Lowe * Our newly bumped template has been anticipated; reset to
147*101e15b5SRichard Lowe * avoid possible "link-through" attack.
148*101e15b5SRichard Lowe */
149*101e15b5SRichard Lowe reset_file_template();
150*101e15b5SRichard Lowe }
151*101e15b5SRichard Lowe
152*101e15b5SRichard Lowe return (0);
153*101e15b5SRichard Lowe }
154*101e15b5SRichard Lowe
155*101e15b5SRichard Lowe void
set_file_template(char ** T)156*101e15b5SRichard Lowe set_file_template(char **T)
157*101e15b5SRichard Lowe {
158*101e15b5SRichard Lowe struct stat s;
159*101e15b5SRichard Lowe int check_tmpdir = 0;
160*101e15b5SRichard Lowe
161*101e15b5SRichard Lowe if (*T != NULL) {
162*101e15b5SRichard Lowe current_tmpdir = strdup(*T);
163*101e15b5SRichard Lowe check_tmpdir = 1;
164*101e15b5SRichard Lowe } else if ((current_tmpdir = getenv("TMPDIR")) != NULL) {
165*101e15b5SRichard Lowe check_tmpdir = 1;
166*101e15b5SRichard Lowe } else {
167*101e15b5SRichard Lowe current_tmpdir = (char *)default_tmpdir;
168*101e15b5SRichard Lowe }
169*101e15b5SRichard Lowe
170*101e15b5SRichard Lowe /*
171*101e15b5SRichard Lowe * Check that the temporary directory given exists, and is a directory.
172*101e15b5SRichard Lowe */
173*101e15b5SRichard Lowe if (check_tmpdir) {
174*101e15b5SRichard Lowe if (stat(current_tmpdir, &s) != 0) {
175*101e15b5SRichard Lowe warn(gettext("cannot stat temporary directory %s"),
176*101e15b5SRichard Lowe current_tmpdir);
177*101e15b5SRichard Lowe
178*101e15b5SRichard Lowe current_tmpdir = (char *)default_tmpdir;
179*101e15b5SRichard Lowe } else if (!S_ISDIR(s.st_mode)) {
180*101e15b5SRichard Lowe warn(gettext("%s is not a directory; "
181*101e15b5SRichard Lowe "using default temporary directory"),
182*101e15b5SRichard Lowe current_tmpdir);
183*101e15b5SRichard Lowe
184*101e15b5SRichard Lowe current_tmpdir = (char *)default_tmpdir;
185*101e15b5SRichard Lowe }
186*101e15b5SRichard Lowe }
187*101e15b5SRichard Lowe
188*101e15b5SRichard Lowe ASSERT(current_tmpdir != NULL);
189*101e15b5SRichard Lowe
190*101e15b5SRichard Lowe current_template = safe_realloc(NULL, strlen(current_tmpdir)
191*101e15b5SRichard Lowe + strlen(default_template) + strlen(default_template_count) + 1);
192*101e15b5SRichard Lowe
193*101e15b5SRichard Lowe reset_file_template();
194*101e15b5SRichard Lowe }
195*101e15b5SRichard Lowe
196*101e15b5SRichard Lowe char *
get_file_template()197*101e15b5SRichard Lowe get_file_template()
198*101e15b5SRichard Lowe {
199*101e15b5SRichard Lowe return (current_template);
200*101e15b5SRichard Lowe }
201*101e15b5SRichard Lowe
202*101e15b5SRichard Lowe /*
203*101e15b5SRichard Lowe * Output guard routines.
204*101e15b5SRichard Lowe */
205*101e15b5SRichard Lowe void
establish_output_guard(sort_t * S)206*101e15b5SRichard Lowe establish_output_guard(sort_t *S)
207*101e15b5SRichard Lowe {
208*101e15b5SRichard Lowe struct stat output_stat;
209*101e15b5SRichard Lowe
210*101e15b5SRichard Lowe if (S->m_output_to_stdout)
211*101e15b5SRichard Lowe return;
212*101e15b5SRichard Lowe
213*101e15b5SRichard Lowe if (stat(S->m_output_filename, &output_stat) == 0) {
214*101e15b5SRichard Lowe stream_t *strp = S->m_input_streams;
215*101e15b5SRichard Lowe
216*101e15b5SRichard Lowe while (strp != NULL) {
217*101e15b5SRichard Lowe /*
218*101e15b5SRichard Lowe * We needn't protect an empty file.
219*101e15b5SRichard Lowe */
220*101e15b5SRichard Lowe if (!(strp->s_status & STREAM_NOTFILE) &&
221*101e15b5SRichard Lowe strp->s_dev == output_stat.st_dev &&
222*101e15b5SRichard Lowe strp->s_ino == output_stat.st_ino &&
223*101e15b5SRichard Lowe strp->s_filesize > 0) {
224*101e15b5SRichard Lowe output_guard_filename = S->m_output_filename;
225*101e15b5SRichard Lowe output_guard_size = strp->s_filesize;
226*101e15b5SRichard Lowe
227*101e15b5SRichard Lowe ASSERT(output_guard_filename != NULL);
228*101e15b5SRichard Lowe
229*101e15b5SRichard Lowe if (bump_file_template() < 0)
230*101e15b5SRichard Lowe die(EMSG_TEMPORARY);
231*101e15b5SRichard Lowe
232*101e15b5SRichard Lowe if ((strp->s_filename = output_guard_tempname =
233*101e15b5SRichard Lowe strdup(get_file_template())) == NULL)
234*101e15b5SRichard Lowe die(EMSG_ALLOC);
235*101e15b5SRichard Lowe
236*101e15b5SRichard Lowe xcp(output_guard_tempname,
237*101e15b5SRichard Lowe output_guard_filename, output_guard_size);
238*101e15b5SRichard Lowe
239*101e15b5SRichard Lowe output_guard_copy_complete = 1;
240*101e15b5SRichard Lowe
241*101e15b5SRichard Lowe return;
242*101e15b5SRichard Lowe }
243*101e15b5SRichard Lowe strp = strp->s_next;
244*101e15b5SRichard Lowe }
245*101e15b5SRichard Lowe }
246*101e15b5SRichard Lowe }
247*101e15b5SRichard Lowe
248*101e15b5SRichard Lowe void
remove_output_guard()249*101e15b5SRichard Lowe remove_output_guard()
250*101e15b5SRichard Lowe {
251*101e15b5SRichard Lowe if (output_guard_tempname && unlink(output_guard_tempname) == -1)
252*101e15b5SRichard Lowe warn(gettext("unable to unlink %s"), output_guard_tempname);
253*101e15b5SRichard Lowe
254*101e15b5SRichard Lowe output_guard_tempname = NULL;
255*101e15b5SRichard Lowe }
256*101e15b5SRichard Lowe
257*101e15b5SRichard Lowe void
set_cleanup_chain(stream_t ** strp)258*101e15b5SRichard Lowe set_cleanup_chain(stream_t **strp)
259*101e15b5SRichard Lowe {
260*101e15b5SRichard Lowe ASSERT(strp != NULL);
261*101e15b5SRichard Lowe
262*101e15b5SRichard Lowe cleanup_chain = strp;
263*101e15b5SRichard Lowe }
264*101e15b5SRichard Lowe
265*101e15b5SRichard Lowe /*
266*101e15b5SRichard Lowe * atexit_handler() cleans up any temporary files outstanding after a fatal
267*101e15b5SRichard Lowe * signal, a call to die() or at exit(). To preserve the input file under low
268*101e15b5SRichard Lowe * storage conditions (and both the output file and the temporary files are
269*101e15b5SRichard Lowe * directed at the same filesystem), we remove all temporary files but the
270*101e15b5SRichard Lowe * output guard first, and then restore the original file. Of course, this is
271*101e15b5SRichard Lowe * not foolproof, as another writer may have exhausted storage.
272*101e15b5SRichard Lowe */
273*101e15b5SRichard Lowe void
atexit_handler()274*101e15b5SRichard Lowe atexit_handler()
275*101e15b5SRichard Lowe {
276*101e15b5SRichard Lowe stream_t *strp;
277*101e15b5SRichard Lowe
278*101e15b5SRichard Lowe if (cleanup_chain && *cleanup_chain)
279*101e15b5SRichard Lowe for (strp = *cleanup_chain; strp != NULL; strp = strp->s_next)
280*101e15b5SRichard Lowe stream_unlink_temporary(strp);
281*101e15b5SRichard Lowe
282*101e15b5SRichard Lowe if (output_guard_tempname) {
283*101e15b5SRichard Lowe if (output_guard_copy_complete)
284*101e15b5SRichard Lowe xcp(output_guard_filename, output_guard_tempname,
285*101e15b5SRichard Lowe output_guard_size);
286*101e15b5SRichard Lowe
287*101e15b5SRichard Lowe remove_output_guard();
288*101e15b5SRichard Lowe }
289*101e15b5SRichard Lowe
290*101e15b5SRichard Lowe __S(stats_display());
291*101e15b5SRichard Lowe }
292*101e15b5SRichard Lowe
293*101e15b5SRichard Lowe size_t
strtomem(char * S)294*101e15b5SRichard Lowe strtomem(char *S)
295*101e15b5SRichard Lowe {
296*101e15b5SRichard Lowe const char *format_str = "%lf%c";
297*101e15b5SRichard Lowe double val = 0.0;
298*101e15b5SRichard Lowe size_t retval;
299*101e15b5SRichard Lowe char units = 'k';
300*101e15b5SRichard Lowe size_t phys_total = sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE);
301*101e15b5SRichard Lowe
302*101e15b5SRichard Lowe if (sscanf(S, format_str, &val, &units) < 1 || val < 0)
303*101e15b5SRichard Lowe return (0);
304*101e15b5SRichard Lowe
305*101e15b5SRichard Lowe if (units == '%') {
306*101e15b5SRichard Lowe if (val < 0 || val > 100)
307*101e15b5SRichard Lowe return (0);
308*101e15b5SRichard Lowe val *= phys_total / 100;
309*101e15b5SRichard Lowe } else
310*101e15b5SRichard Lowe switch (units) {
311*101e15b5SRichard Lowe case 't' : /* terabytes */
312*101e15b5SRichard Lowe case 'T' :
313*101e15b5SRichard Lowe val *= 1024;
314*101e15b5SRichard Lowe /*FALLTHROUGH*/
315*101e15b5SRichard Lowe case 'g' : /* gigabytes */
316*101e15b5SRichard Lowe case 'G' :
317*101e15b5SRichard Lowe val *= 1024;
318*101e15b5SRichard Lowe /*FALLTHROUGH*/
319*101e15b5SRichard Lowe case 'm' : /* megabytes */
320*101e15b5SRichard Lowe case 'M' :
321*101e15b5SRichard Lowe val *= 1024;
322*101e15b5SRichard Lowe /*FALLTHROUGH*/
323*101e15b5SRichard Lowe case 'k' : /* kilobytes */
324*101e15b5SRichard Lowe case 'K' :
325*101e15b5SRichard Lowe val *= 1024;
326*101e15b5SRichard Lowe /*FALLTHROUGH*/
327*101e15b5SRichard Lowe case 'b' : /* bytes */
328*101e15b5SRichard Lowe case 'B' :
329*101e15b5SRichard Lowe break;
330*101e15b5SRichard Lowe default :
331*101e15b5SRichard Lowe /*
332*101e15b5SRichard Lowe * default is kilobytes
333*101e15b5SRichard Lowe */
334*101e15b5SRichard Lowe val *= 1024;
335*101e15b5SRichard Lowe break;
336*101e15b5SRichard Lowe }
337*101e15b5SRichard Lowe
338*101e15b5SRichard Lowe if (val > SIZE_MAX)
339*101e15b5SRichard Lowe return (0);
340*101e15b5SRichard Lowe
341*101e15b5SRichard Lowe retval = (size_t)val;
342*101e15b5SRichard Lowe
343*101e15b5SRichard Lowe return (retval);
344*101e15b5SRichard Lowe }
345*101e15b5SRichard Lowe
346*101e15b5SRichard Lowe size_t
available_memory(size_t mem_limit)347*101e15b5SRichard Lowe available_memory(size_t mem_limit)
348*101e15b5SRichard Lowe {
349*101e15b5SRichard Lowe size_t phys_avail = sysconf(_SC_AVPHYS_PAGES) * sysconf(_SC_PAGESIZE);
350*101e15b5SRichard Lowe size_t avail;
351*101e15b5SRichard Lowe
352*101e15b5SRichard Lowe if (mem_limit != 0) {
353*101e15b5SRichard Lowe #ifdef DEBUG
354*101e15b5SRichard Lowe /*
355*101e15b5SRichard Lowe * In the debug case, we want to test the temporary files
356*101e15b5SRichard Lowe * handling, so no lower bound on the memory limit is imposed.
357*101e15b5SRichard Lowe */
358*101e15b5SRichard Lowe avail = mem_limit;
359*101e15b5SRichard Lowe #else
360*101e15b5SRichard Lowe avail = MAX(64 * KILOBYTE, mem_limit);
361*101e15b5SRichard Lowe #endif /* DEBUG */
362*101e15b5SRichard Lowe } else {
363*101e15b5SRichard Lowe avail = MAX(64 * KILOBYTE, MIN(AV_MEM_MULTIPLIER * phys_avail /
364*101e15b5SRichard Lowe AV_MEM_DIVISOR, 16 * MEGABYTE));
365*101e15b5SRichard Lowe }
366*101e15b5SRichard Lowe
367*101e15b5SRichard Lowe __S(stats_set_available_memory(avail));
368*101e15b5SRichard Lowe
369*101e15b5SRichard Lowe return (avail);
370*101e15b5SRichard Lowe }
371*101e15b5SRichard Lowe
372*101e15b5SRichard Lowe void
set_memory_ratio(sort_t * S,int * numerator,int * denominator)373*101e15b5SRichard Lowe set_memory_ratio(sort_t *S, int *numerator, int *denominator)
374*101e15b5SRichard Lowe {
375*101e15b5SRichard Lowe if (S->m_c_locale) {
376*101e15b5SRichard Lowe *numerator = CHAR_AVG_LINE;
377*101e15b5SRichard Lowe *denominator = sizeof (line_rec_t) + sizeof (line_rec_t *) +
378*101e15b5SRichard Lowe CHAR_AVG_LINE + CHAR_AVG_LINE;
379*101e15b5SRichard Lowe return;
380*101e15b5SRichard Lowe }
381*101e15b5SRichard Lowe
382*101e15b5SRichard Lowe if (S->m_single_byte_locale) {
383*101e15b5SRichard Lowe *numerator = CHAR_AVG_LINE;
384*101e15b5SRichard Lowe *denominator = sizeof (line_rec_t) + sizeof (line_rec_t *) +
385*101e15b5SRichard Lowe CHAR_AVG_LINE + XFRM_MULTIPLIER * CHAR_AVG_LINE;
386*101e15b5SRichard Lowe return;
387*101e15b5SRichard Lowe }
388*101e15b5SRichard Lowe
389*101e15b5SRichard Lowe *numerator = WCHAR_AVG_LINE;
390*101e15b5SRichard Lowe *denominator = sizeof (line_rec_t) + sizeof (line_rec_t *) +
391*101e15b5SRichard Lowe WCHAR_AVG_LINE + WCHAR_AVG_LINE;
392*101e15b5SRichard Lowe }
393*101e15b5SRichard Lowe
394*101e15b5SRichard Lowe void *
safe_realloc(void * ptr,size_t sz)395*101e15b5SRichard Lowe safe_realloc(void *ptr, size_t sz)
396*101e15b5SRichard Lowe {
397*101e15b5SRichard Lowe /*
398*101e15b5SRichard Lowe * safe_realloc() is not meant as an alternative free() mechanism--we
399*101e15b5SRichard Lowe * disallow reallocations to size zero.
400*101e15b5SRichard Lowe */
401*101e15b5SRichard Lowe ASSERT(sz != 0);
402*101e15b5SRichard Lowe
403*101e15b5SRichard Lowe if ((ptr = realloc(ptr, sz)) != NULL)
404*101e15b5SRichard Lowe return (ptr);
405*101e15b5SRichard Lowe
406*101e15b5SRichard Lowe die(gettext("unable to reallocate buffer"));
407*101e15b5SRichard Lowe /*NOTREACHED*/
408*101e15b5SRichard Lowe return (NULL); /* keep gcc happy */
409*101e15b5SRichard Lowe }
410*101e15b5SRichard Lowe
411*101e15b5SRichard Lowe void
safe_free(void * ptr)412*101e15b5SRichard Lowe safe_free(void *ptr)
413*101e15b5SRichard Lowe {
414*101e15b5SRichard Lowe if (ptr)
415*101e15b5SRichard Lowe free(ptr);
416*101e15b5SRichard Lowe }
417*101e15b5SRichard Lowe
418*101e15b5SRichard Lowe void *
xzmap(void * addr,size_t len,int prot,int flags,off_t off)419*101e15b5SRichard Lowe xzmap(void *addr, size_t len, int prot, int flags, off_t off)
420*101e15b5SRichard Lowe {
421*101e15b5SRichard Lowe void *pa;
422*101e15b5SRichard Lowe
423*101e15b5SRichard Lowe pa = mmap(addr, len, prot, flags | MAP_ANON, -1, off);
424*101e15b5SRichard Lowe if (pa == MAP_FAILED)
425*101e15b5SRichard Lowe die(gettext("can't mmap anonymous memory"));
426*101e15b5SRichard Lowe
427*101e15b5SRichard Lowe return (pa);
428*101e15b5SRichard Lowe }
429*101e15b5SRichard Lowe
430*101e15b5SRichard Lowe void
usage()431*101e15b5SRichard Lowe usage()
432*101e15b5SRichard Lowe {
433*101e15b5SRichard Lowe (void) fprintf(stderr,
434*101e15b5SRichard Lowe gettext("usage: %s [-cmu] [-o output] [-T directory] [-S mem]"
435*101e15b5SRichard Lowe " [-z recsz]\n\t[-dfiMnr] [-b] [-t char] [-k keydef]"
436*101e15b5SRichard Lowe " [+pos1 [-pos2]] files...\n"), CMDNAME);
437*101e15b5SRichard Lowe exit(E_USAGE);
438*101e15b5SRichard Lowe }
439*101e15b5SRichard Lowe
440*101e15b5SRichard Lowe /*
441*101e15b5SRichard Lowe * hold_file_descriptor() and release_file_descriptor() reserve a single file
442*101e15b5SRichard Lowe * descriptor entry for later use. We issue the hold prior to any loop that has
443*101e15b5SRichard Lowe * an exit condition based on the receipt of EMFILE from an open() call; once we
444*101e15b5SRichard Lowe * have exited, we can release, typically prior to opening a file for output.
445*101e15b5SRichard Lowe */
446*101e15b5SRichard Lowe void
hold_file_descriptor()447*101e15b5SRichard Lowe hold_file_descriptor()
448*101e15b5SRichard Lowe {
449*101e15b5SRichard Lowe ASSERT(held_fd == -1);
450*101e15b5SRichard Lowe
451*101e15b5SRichard Lowe if ((held_fd = open("/dev/null", O_RDONLY)) == -1)
452*101e15b5SRichard Lowe die(gettext("insufficient available file descriptors\n"));
453*101e15b5SRichard Lowe }
454*101e15b5SRichard Lowe
455*101e15b5SRichard Lowe void
release_file_descriptor()456*101e15b5SRichard Lowe release_file_descriptor()
457*101e15b5SRichard Lowe {
458*101e15b5SRichard Lowe ASSERT(held_fd != -1);
459*101e15b5SRichard Lowe
460*101e15b5SRichard Lowe (void) close(held_fd);
461*101e15b5SRichard Lowe held_fd = -1;
462*101e15b5SRichard Lowe }
463*101e15b5SRichard Lowe
464*101e15b5SRichard Lowe void
copy_line_rec(const line_rec_t * a,line_rec_t * b)465*101e15b5SRichard Lowe copy_line_rec(const line_rec_t *a, line_rec_t *b)
466*101e15b5SRichard Lowe {
467*101e15b5SRichard Lowe (void) memcpy(b, a, sizeof (line_rec_t));
468*101e15b5SRichard Lowe }
469*101e15b5SRichard Lowe
470*101e15b5SRichard Lowe void
trip_eof(FILE * f)471*101e15b5SRichard Lowe trip_eof(FILE *f)
472*101e15b5SRichard Lowe {
473*101e15b5SRichard Lowe if (feof(f))
474*101e15b5SRichard Lowe return;
475*101e15b5SRichard Lowe
476*101e15b5SRichard Lowe (void) ungetc(fgetc(f), f);
477*101e15b5SRichard Lowe }
478*101e15b5SRichard Lowe
479*101e15b5SRichard Lowe /*
480*101e15b5SRichard Lowe * int cxwrite(int, char *, size_t)
481*101e15b5SRichard Lowe *
482*101e15b5SRichard Lowe * Overview
483*101e15b5SRichard Lowe * cxwrite() implements a buffered version of fwrite(ptr, nbytes, 1, .) on
484*101e15b5SRichard Lowe * file descriptors. It returns -1 in the case that the write() fails to
485*101e15b5SRichard Lowe * write the current buffer contents. cxwrite() must be flushed before being
486*101e15b5SRichard Lowe * applied to a new file descriptor.
487*101e15b5SRichard Lowe *
488*101e15b5SRichard Lowe * Return values
489*101e15b5SRichard Lowe * 0 on success, -1 on error.
490*101e15b5SRichard Lowe */
491*101e15b5SRichard Lowe int
cxwrite(int fd,char * ptr,size_t nbytes)492*101e15b5SRichard Lowe cxwrite(int fd, char *ptr, size_t nbytes)
493*101e15b5SRichard Lowe {
494*101e15b5SRichard Lowe static char buffer[XBUFFER_SIZE];
495*101e15b5SRichard Lowe static size_t offset = 0;
496*101e15b5SRichard Lowe size_t mbytes;
497*101e15b5SRichard Lowe
498*101e15b5SRichard Lowe if (ptr == NULL) {
499*101e15b5SRichard Lowe errno = 0;
500*101e15b5SRichard Lowe while (offset -= write(fd, buffer, offset)) {
501*101e15b5SRichard Lowe if (errno)
502*101e15b5SRichard Lowe break;
503*101e15b5SRichard Lowe }
504*101e15b5SRichard Lowe
505*101e15b5SRichard Lowe if (offset)
506*101e15b5SRichard Lowe return (-1);
507*101e15b5SRichard Lowe
508*101e15b5SRichard Lowe return (0);
509*101e15b5SRichard Lowe }
510*101e15b5SRichard Lowe
511*101e15b5SRichard Lowe while (nbytes != 0) {
512*101e15b5SRichard Lowe if (offset + nbytes > XBUFFER_SIZE)
513*101e15b5SRichard Lowe mbytes = XBUFFER_SIZE - offset;
514*101e15b5SRichard Lowe else
515*101e15b5SRichard Lowe mbytes = nbytes;
516*101e15b5SRichard Lowe
517*101e15b5SRichard Lowe (void) memcpy(buffer + offset, ptr, mbytes);
518*101e15b5SRichard Lowe nbytes -= mbytes;
519*101e15b5SRichard Lowe offset += mbytes;
520*101e15b5SRichard Lowe ptr += mbytes;
521*101e15b5SRichard Lowe
522*101e15b5SRichard Lowe if (nbytes) {
523*101e15b5SRichard Lowe errno = 0;
524*101e15b5SRichard Lowe while (offset -= write(fd, buffer, offset)) {
525*101e15b5SRichard Lowe if (errno)
526*101e15b5SRichard Lowe break;
527*101e15b5SRichard Lowe }
528*101e15b5SRichard Lowe
529*101e15b5SRichard Lowe if (offset)
530*101e15b5SRichard Lowe return (-1);
531*101e15b5SRichard Lowe }
532*101e15b5SRichard Lowe }
533*101e15b5SRichard Lowe
534*101e15b5SRichard Lowe return (0);
535*101e15b5SRichard Lowe }
536*101e15b5SRichard Lowe
537*101e15b5SRichard Lowe /*
538*101e15b5SRichard Lowe * int wxwrite(int, wchar_t *)
539*101e15b5SRichard Lowe *
540*101e15b5SRichard Lowe * Overview
541*101e15b5SRichard Lowe * wxwrite() implements a buffered write() function for null-terminated wide
542*101e15b5SRichard Lowe * character buffers with similar calling semantics to cxwrite(). It returns
543*101e15b5SRichard Lowe * -1 in the case that it fails to write the current buffer contents.
544*101e15b5SRichard Lowe * wxwrite() must be flushed before being applied to a new file descriptor.
545*101e15b5SRichard Lowe *
546*101e15b5SRichard Lowe * Return values
547*101e15b5SRichard Lowe * 0 on success, -1 on error.
548*101e15b5SRichard Lowe */
549*101e15b5SRichard Lowe int
wxwrite(int fd,wchar_t * ptr)550*101e15b5SRichard Lowe wxwrite(int fd, wchar_t *ptr)
551*101e15b5SRichard Lowe {
552*101e15b5SRichard Lowe static char *convert_buffer;
553*101e15b5SRichard Lowe static size_t convert_bufsize = 1024;
554*101e15b5SRichard Lowe size_t req_bufsize;
555*101e15b5SRichard Lowe
556*101e15b5SRichard Lowe if (ptr == NULL)
557*101e15b5SRichard Lowe return (cxwrite(fd, NULL, 0));
558*101e15b5SRichard Lowe
559*101e15b5SRichard Lowe if (convert_buffer == NULL)
560*101e15b5SRichard Lowe convert_buffer = safe_realloc(NULL, convert_bufsize);
561*101e15b5SRichard Lowe /*
562*101e15b5SRichard Lowe * We use wcstombs(NULL, ., .) to verify that we have an adequate
563*101e15b5SRichard Lowe * buffer size for the conversion. Since this buffer was converted into
564*101e15b5SRichard Lowe * wide character format earlier, we can safely assume that the buffer
565*101e15b5SRichard Lowe * can be converted back to the external multibyte form.
566*101e15b5SRichard Lowe */
567*101e15b5SRichard Lowe req_bufsize = wcstombs(NULL, ptr, convert_bufsize);
568*101e15b5SRichard Lowe if (req_bufsize > convert_bufsize) {
569*101e15b5SRichard Lowe convert_bufsize = req_bufsize + 1;
570*101e15b5SRichard Lowe convert_buffer = safe_realloc(convert_buffer, convert_bufsize);
571*101e15b5SRichard Lowe }
572*101e15b5SRichard Lowe
573*101e15b5SRichard Lowe (void) wcstombs(convert_buffer, ptr, convert_bufsize);
574*101e15b5SRichard Lowe
575*101e15b5SRichard Lowe return (cxwrite(fd, convert_buffer, req_bufsize));
576*101e15b5SRichard Lowe }
577*101e15b5SRichard Lowe
578*101e15b5SRichard Lowe int
xstreql(const char * a,const char * b)579*101e15b5SRichard Lowe xstreql(const char *a, const char *b)
580*101e15b5SRichard Lowe {
581*101e15b5SRichard Lowe return (strcmp(a, b) == 0);
582*101e15b5SRichard Lowe }
583*101e15b5SRichard Lowe
584*101e15b5SRichard Lowe int
xstrneql(const char * a,const char * b,const size_t l)585*101e15b5SRichard Lowe xstrneql(const char *a, const char *b, const size_t l)
586*101e15b5SRichard Lowe {
587*101e15b5SRichard Lowe return (strncmp(a, b, l) == 0);
588*101e15b5SRichard Lowe }
589*101e15b5SRichard Lowe
590*101e15b5SRichard Lowe char *
xstrnchr(const char * S,const int c,const size_t n)591*101e15b5SRichard Lowe xstrnchr(const char *S, const int c, const size_t n)
592*101e15b5SRichard Lowe {
593*101e15b5SRichard Lowe const char *eS = S + n;
594*101e15b5SRichard Lowe
595*101e15b5SRichard Lowe do {
596*101e15b5SRichard Lowe if (*S == (char)c)
597*101e15b5SRichard Lowe return ((char *)S);
598*101e15b5SRichard Lowe } while (++S < eS);
599*101e15b5SRichard Lowe
600*101e15b5SRichard Lowe return (NULL);
601*101e15b5SRichard Lowe }
602*101e15b5SRichard Lowe
603*101e15b5SRichard Lowe void
xstrninv(char * s,ssize_t start,ssize_t length)604*101e15b5SRichard Lowe xstrninv(char *s, ssize_t start, ssize_t length)
605*101e15b5SRichard Lowe {
606*101e15b5SRichard Lowe ssize_t i;
607*101e15b5SRichard Lowe
608*101e15b5SRichard Lowe for (i = start; i < start + length; i++)
609*101e15b5SRichard Lowe s[i] = UCHAR_MAX - s[i];
610*101e15b5SRichard Lowe }
611*101e15b5SRichard Lowe
612*101e15b5SRichard Lowe int
xwcsneql(const wchar_t * a,const wchar_t * b,const size_t length)613*101e15b5SRichard Lowe xwcsneql(const wchar_t *a, const wchar_t *b, const size_t length)
614*101e15b5SRichard Lowe {
615*101e15b5SRichard Lowe return (wcsncmp(a, b, length) == 0);
616*101e15b5SRichard Lowe }
617*101e15b5SRichard Lowe
618*101e15b5SRichard Lowe wchar_t *
xwsnchr(const wchar_t * ws,const wint_t wc,const size_t n)619*101e15b5SRichard Lowe xwsnchr(const wchar_t *ws, const wint_t wc, const size_t n)
620*101e15b5SRichard Lowe {
621*101e15b5SRichard Lowe const wchar_t *ews = ws + n;
622*101e15b5SRichard Lowe
623*101e15b5SRichard Lowe do {
624*101e15b5SRichard Lowe if (*ws == (wchar_t)wc)
625*101e15b5SRichard Lowe return ((wchar_t *)ws);
626*101e15b5SRichard Lowe } while (++ws < ews);
627*101e15b5SRichard Lowe
628*101e15b5SRichard Lowe return (NULL);
629*101e15b5SRichard Lowe }
630*101e15b5SRichard Lowe
631*101e15b5SRichard Lowe void
xwcsninv(wchar_t * s,ssize_t start,ssize_t length)632*101e15b5SRichard Lowe xwcsninv(wchar_t *s, ssize_t start, ssize_t length)
633*101e15b5SRichard Lowe {
634*101e15b5SRichard Lowe ssize_t i;
635*101e15b5SRichard Lowe
636*101e15b5SRichard Lowe for (i = start; i < start + length; i++)
637*101e15b5SRichard Lowe s[i] = WCHAR_MAX - s[i];
638*101e15b5SRichard Lowe }
639*101e15b5SRichard Lowe
640*101e15b5SRichard Lowe #ifdef _LITTLE_ENDIAN
641*101e15b5SRichard Lowe void
xwcsntomsb(wchar_t * s,ssize_t length)642*101e15b5SRichard Lowe xwcsntomsb(wchar_t *s, ssize_t length)
643*101e15b5SRichard Lowe {
644*101e15b5SRichard Lowe ssize_t i;
645*101e15b5SRichard Lowe
646*101e15b5SRichard Lowe ASSERT(sizeof (wchar_t) == sizeof (uint32_t));
647*101e15b5SRichard Lowe
648*101e15b5SRichard Lowe for (i = 0; i < length; i++, s++) {
649*101e15b5SRichard Lowe char *t = (char *)s;
650*101e15b5SRichard Lowe char u;
651*101e15b5SRichard Lowe
652*101e15b5SRichard Lowe u = *t;
653*101e15b5SRichard Lowe *t = *(t + 3);
654*101e15b5SRichard Lowe *(t + 3) = u;
655*101e15b5SRichard Lowe
656*101e15b5SRichard Lowe u = *(t + 1);
657*101e15b5SRichard Lowe *(t + 1) = *(t + 2);
658*101e15b5SRichard Lowe *(t + 2) = u;
659*101e15b5SRichard Lowe }
660*101e15b5SRichard Lowe }
661*101e15b5SRichard Lowe #endif /* _LITTLE_ENDIAN */
662*101e15b5SRichard Lowe
663*101e15b5SRichard Lowe wchar_t *
xmemwchar(wchar_t * s,wchar_t w,ssize_t length)664*101e15b5SRichard Lowe xmemwchar(wchar_t *s, wchar_t w, ssize_t length)
665*101e15b5SRichard Lowe {
666*101e15b5SRichard Lowe ssize_t i = length;
667*101e15b5SRichard Lowe
668*101e15b5SRichard Lowe while (--i > 0) {
669*101e15b5SRichard Lowe if (*s == w)
670*101e15b5SRichard Lowe return (s);
671*101e15b5SRichard Lowe s++;
672*101e15b5SRichard Lowe }
673*101e15b5SRichard Lowe
674*101e15b5SRichard Lowe return (NULL);
675*101e15b5SRichard Lowe }
676*101e15b5SRichard Lowe
677*101e15b5SRichard Lowe void
xcp(char * dst,char * src,off_t size)678*101e15b5SRichard Lowe xcp(char *dst, char *src, off_t size)
679*101e15b5SRichard Lowe {
680*101e15b5SRichard Lowe int fd_in, fd_out;
681*101e15b5SRichard Lowe void *mm_in;
682*101e15b5SRichard Lowe size_t chunksize = 2 * MEGABYTE;
683*101e15b5SRichard Lowe int i;
684*101e15b5SRichard Lowe ssize_t nchunks = size / chunksize;
685*101e15b5SRichard Lowe ssize_t lastchunk = size % chunksize;
686*101e15b5SRichard Lowe
687*101e15b5SRichard Lowe if (dst == NULL || src == NULL)
688*101e15b5SRichard Lowe return;
689*101e15b5SRichard Lowe
690*101e15b5SRichard Lowe if ((fd_in = open(src, O_RDONLY)) < 0)
691*101e15b5SRichard Lowe die(EMSG_OPEN, src);
692*101e15b5SRichard Lowe if ((fd_out = open(dst, O_RDWR | O_CREAT | O_TRUNC, OUTPUT_MODE)) < 0)
693*101e15b5SRichard Lowe die(EMSG_OPEN, dst);
694*101e15b5SRichard Lowe
695*101e15b5SRichard Lowe for (i = 0; i < nchunks; i++) {
696*101e15b5SRichard Lowe if ((mm_in = mmap(0, chunksize, PROT_READ, MAP_SHARED, fd_in,
697*101e15b5SRichard Lowe i * chunksize)) == MAP_FAILED)
698*101e15b5SRichard Lowe die(EMSG_MMAP, src);
699*101e15b5SRichard Lowe
700*101e15b5SRichard Lowe if (write(fd_out, mm_in, chunksize) != chunksize)
701*101e15b5SRichard Lowe die(EMSG_WRITE, dst);
702*101e15b5SRichard Lowe
703*101e15b5SRichard Lowe (void) munmap(mm_in, chunksize);
704*101e15b5SRichard Lowe }
705*101e15b5SRichard Lowe
706*101e15b5SRichard Lowe if (lastchunk) {
707*101e15b5SRichard Lowe if ((mm_in = mmap(0, lastchunk, PROT_READ, MAP_SHARED, fd_in,
708*101e15b5SRichard Lowe nchunks * chunksize)) == MAP_FAILED)
709*101e15b5SRichard Lowe die(EMSG_MMAP, src);
710*101e15b5SRichard Lowe
711*101e15b5SRichard Lowe if (write(fd_out, mm_in, lastchunk) != lastchunk)
712*101e15b5SRichard Lowe die(EMSG_WRITE, dst);
713*101e15b5SRichard Lowe
714*101e15b5SRichard Lowe (void) munmap(mm_in, lastchunk);
715*101e15b5SRichard Lowe }
716*101e15b5SRichard Lowe
717*101e15b5SRichard Lowe (void) close(fd_in);
718*101e15b5SRichard Lowe
719*101e15b5SRichard Lowe if (close(fd_out) == -1)
720*101e15b5SRichard Lowe die(EMSG_CLOSE, dst);
721*101e15b5SRichard Lowe }
722*101e15b5SRichard Lowe
723*101e15b5SRichard Lowe /*PRINTFLIKE1*/
724*101e15b5SRichard Lowe void
warn(const char * format,...)725*101e15b5SRichard Lowe warn(const char *format, ...)
726*101e15b5SRichard Lowe {
727*101e15b5SRichard Lowe int err = errno;
728*101e15b5SRichard Lowe va_list alist;
729*101e15b5SRichard Lowe
730*101e15b5SRichard Lowe if (pname != NULL)
731*101e15b5SRichard Lowe (void) fprintf(stderr, gettext(PNAME_FMT), pname);
732*101e15b5SRichard Lowe
733*101e15b5SRichard Lowe va_start(alist, format);
734*101e15b5SRichard Lowe (void) vfprintf(stderr, format, alist);
735*101e15b5SRichard Lowe va_end(alist);
736*101e15b5SRichard Lowe
737*101e15b5SRichard Lowe if (strrchr(format, '\n') == NULL)
738*101e15b5SRichard Lowe (void) fprintf(stderr, gettext(ERRNO_FMT), strerror(err));
739*101e15b5SRichard Lowe }
740*101e15b5SRichard Lowe
741*101e15b5SRichard Lowe /*PRINTFLIKE1*/
742*101e15b5SRichard Lowe void
die(const char * format,...)743*101e15b5SRichard Lowe die(const char *format, ...)
744*101e15b5SRichard Lowe {
745*101e15b5SRichard Lowe int err = errno;
746*101e15b5SRichard Lowe va_list alist;
747*101e15b5SRichard Lowe
748*101e15b5SRichard Lowe if (pname != NULL)
749*101e15b5SRichard Lowe (void) fprintf(stderr, gettext(PNAME_FMT), pname);
750*101e15b5SRichard Lowe
751*101e15b5SRichard Lowe va_start(alist, format);
752*101e15b5SRichard Lowe (void) vfprintf(stderr, format, alist);
753*101e15b5SRichard Lowe va_end(alist);
754*101e15b5SRichard Lowe
755*101e15b5SRichard Lowe if (strrchr(format, '\n') == NULL)
756*101e15b5SRichard Lowe (void) fprintf(stderr, gettext(ERRNO_FMT), strerror(err));
757*101e15b5SRichard Lowe
758*101e15b5SRichard Lowe exit(E_ERROR);
759*101e15b5SRichard Lowe }
760*101e15b5SRichard Lowe
761*101e15b5SRichard Lowe #ifdef DEBUG
762*101e15b5SRichard Lowe /*
763*101e15b5SRichard Lowe * pprintc() is called only by xdump().
764*101e15b5SRichard Lowe */
765*101e15b5SRichard Lowe #define BYTES_PER_LINE 16
766*101e15b5SRichard Lowe static void
pprintc(FILE * fp,char c)767*101e15b5SRichard Lowe pprintc(FILE *fp, char c)
768*101e15b5SRichard Lowe {
769*101e15b5SRichard Lowe if (isspace((uchar_t)c))
770*101e15b5SRichard Lowe (void) fprintf(fp, " ");
771*101e15b5SRichard Lowe else if (isprint((uchar_t)c))
772*101e15b5SRichard Lowe (void) fprintf(fp, "%c", c);
773*101e15b5SRichard Lowe else
774*101e15b5SRichard Lowe (void) fprintf(fp, ".");
775*101e15b5SRichard Lowe }
776*101e15b5SRichard Lowe
777*101e15b5SRichard Lowe static void
pprintwc(FILE * fp,wchar_t c)778*101e15b5SRichard Lowe pprintwc(FILE *fp, wchar_t c)
779*101e15b5SRichard Lowe {
780*101e15b5SRichard Lowe if (iswspace(c))
781*101e15b5SRichard Lowe (void) fprintf(fp, " ");
782*101e15b5SRichard Lowe else if (iswprint(c))
783*101e15b5SRichard Lowe (void) fprintf(fp, "%wc", c);
784*101e15b5SRichard Lowe else
785*101e15b5SRichard Lowe (void) fprintf(fp, ".");
786*101e15b5SRichard Lowe }
787*101e15b5SRichard Lowe
788*101e15b5SRichard Lowe /*
789*101e15b5SRichard Lowe * xdump() is used only for debugging purposes.
790*101e15b5SRichard Lowe */
791*101e15b5SRichard Lowe void
xdump(FILE * fp,uchar_t * buf,size_t bufsize,int wide)792*101e15b5SRichard Lowe xdump(FILE *fp, uchar_t *buf, size_t bufsize, int wide)
793*101e15b5SRichard Lowe {
794*101e15b5SRichard Lowe int i;
795*101e15b5SRichard Lowe size_t nc = 0;
796*101e15b5SRichard Lowe uchar_t d[BYTES_PER_LINE];
797*101e15b5SRichard Lowe
798*101e15b5SRichard Lowe for (; nc < bufsize; buf++) {
799*101e15b5SRichard Lowe d[nc % BYTES_PER_LINE] = *buf;
800*101e15b5SRichard Lowe if (nc % BYTES_PER_LINE == 0) {
801*101e15b5SRichard Lowe (void) fprintf(fp, "%08x:", nc);
802*101e15b5SRichard Lowe }
803*101e15b5SRichard Lowe (void) fprintf(fp, " %02x", *buf);
804*101e15b5SRichard Lowe nc++;
805*101e15b5SRichard Lowe if (nc % BYTES_PER_LINE == 0) {
806*101e15b5SRichard Lowe (void) fprintf(fp, " ");
807*101e15b5SRichard Lowe if (wide) {
808*101e15b5SRichard Lowe for (i = 0; i < BYTES_PER_LINE;
809*101e15b5SRichard Lowe i += sizeof (wchar_t))
810*101e15b5SRichard Lowe pprintwc(fp, *(wchar_t *)(d + i));
811*101e15b5SRichard Lowe } else {
812*101e15b5SRichard Lowe for (i = 0; i < BYTES_PER_LINE; i++)
813*101e15b5SRichard Lowe pprintc(fp, d[i]);
814*101e15b5SRichard Lowe }
815*101e15b5SRichard Lowe (void) fprintf(fp, "\n");
816*101e15b5SRichard Lowe }
817*101e15b5SRichard Lowe }
818*101e15b5SRichard Lowe
819*101e15b5SRichard Lowe for (i = nc % BYTES_PER_LINE; i < BYTES_PER_LINE; i++)
820*101e15b5SRichard Lowe (void) fprintf(fp, " ");
821*101e15b5SRichard Lowe
822*101e15b5SRichard Lowe (void) fprintf(fp, " ");
823*101e15b5SRichard Lowe
824*101e15b5SRichard Lowe if (wide) {
825*101e15b5SRichard Lowe for (i = 0; i < nc % BYTES_PER_LINE; i += sizeof (wchar_t))
826*101e15b5SRichard Lowe pprintwc(fp, *(wchar_t *)(d + i));
827*101e15b5SRichard Lowe } else {
828*101e15b5SRichard Lowe for (i = 0; i < nc % BYTES_PER_LINE; i++)
829*101e15b5SRichard Lowe pprintc(fp, d[i]);
830*101e15b5SRichard Lowe }
831*101e15b5SRichard Lowe
832*101e15b5SRichard Lowe (void) fprintf(fp, "\n");
833*101e15b5SRichard Lowe }
834*101e15b5SRichard Lowe #endif /* DEBUG */
835