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