source: freewrt/tools/paxmirabilis/src/gen_subs.c@ fdd4f59

freewrt_1_0 freewrt_2_0
Last change on this file since fdd4f59 was 9ec66c9, checked in by Thorsten Glaser <tg@…>, 19 years ago

sync with upstream after feeding the patches back

git-svn-id: svn://www.freewrt.org/trunk/freewrt@225 afb5a338-a214-0410-bd46-81f09a774fd1

  • Property mode set to 100644
File size: 10.1 KB
Line 
1/** $MirOS: src/bin/pax/gen_subs.c,v 1.6 2006/07/16 17:58:08 tg Exp $ */
2/* $OpenBSD: gen_subs.c,v 1.18 2005/04/28 06:58:07 otto Exp $ */
3/* $NetBSD: gen_subs.c,v 1.5 1995/03/21 09:07:26 cgd Exp $ */
4
5/*-
6 * Copyright (c) 1992 Keith Muller.
7 * Copyright (c) 1992, 1993
8 * The Regents of the University of California. All rights reserved.
9 *
10 * This code is derived from software contributed to Berkeley by
11 * Keith Muller of the University of California, San Diego.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37
38#include <sys/types.h>
39#include <sys/time.h>
40#include <sys/stat.h>
41#include <sys/param.h>
42#include <stdio.h>
43#include <tzfile.h>
44#ifdef __INTERIX
45#include <utmpx.h>
46#else
47#include <utmp.h>
48#endif
49#include <unistd.h>
50#include <stdlib.h>
51#include <string.h>
52#ifndef __GLIBC__
53#include <vis.h>
54#endif
55#include "pax.h"
56#include "extern.h"
57
58__SCCSID("@(#)gen_subs.c 8.1 (Berkeley) 5/31/93");
59__RCSID("$MirOS: src/bin/pax/gen_subs.c,v 1.6 2006/07/16 17:58:08 tg Exp $");
60
61#ifdef __GLIBC__
62void strmode(mode_t, char *);
63#endif
64
65/*
66 * a collection of general purpose subroutines used by pax
67 */
68
69/*
70 * constants used by ls_list() when printing out archive members
71 */
72#define MODELEN 20
73#define DATELEN 64
74#define SIXMONTHS ((DAYSPERNYEAR / 2) * SECSPERDAY)
75#define CURFRMT "%b %e %H:%M"
76#define OLDFRMT "%b %e %Y"
77#define NAME_WIDTH 8
78
79/*
80 * ls_list()
81 * list the members of an archive in ls format
82 */
83
84void
85ls_list(ARCHD *arcn, time_t now, FILE *fp)
86{
87 struct stat *sbp;
88 char f_mode[MODELEN];
89 char f_date[DATELEN];
90 const char *timefrmt;
91 int term;
92
93 term = zeroflag ? '\0' : '\n'; /* path termination character */
94
95 /*
96 * if not verbose, just print the file name
97 */
98 if (!vflag) {
99 if (zeroflag)
100 (void)fputs(arcn->name, fp);
101 else
102 safe_print(arcn->name, fp);
103 (void)putc(term, fp);
104 (void)fflush(fp);
105 return;
106 }
107
108 /*
109 * user wants long mode
110 */
111 sbp = &(arcn->sb);
112 strmode(sbp->st_mode, f_mode);
113
114 if (ltmfrmt == NULL) {
115 /*
116 * no locale specified format. time format based on age
117 * compared to the time pax was started.
118 */
119 if ((sbp->st_mtime + SIXMONTHS) <= now)
120 timefrmt = OLDFRMT;
121 else
122 timefrmt = CURFRMT;
123 } else
124 timefrmt = ltmfrmt;
125
126 /*
127 * print file mode, link count, uid, gid and time
128 */
129 if (strftime(f_date,DATELEN,timefrmt,localtime(&(sbp->st_mtime))) == 0)
130 f_date[0] = '\0';
131 (void)fprintf(fp, "%s%2u %-*.*s %-*.*s ", f_mode,
132 (unsigned)sbp->st_nlink,
133 NAME_WIDTH, UT_NAMESIZE, name_uid(sbp->st_uid, 1),
134 NAME_WIDTH, UT_NAMESIZE, name_gid(sbp->st_gid, 1));
135
136 /*
137 * print device id's for devices, or sizes for other nodes
138 */
139 if ((arcn->type == PAX_CHR) || (arcn->type == PAX_BLK))
140 (void)fprintf(fp, "%4lu,%4lu ", (unsigned long)MAJOR(sbp->st_rdev),
141 (unsigned long)MINOR(sbp->st_rdev));
142 else {
143# ifdef LONG_OFF_T
144 (void)fprintf(fp, "%9lu ", sbp->st_size);
145# else
146 (void)fprintf(fp, "%9qu ", sbp->st_size);
147# endif
148 }
149
150 /*
151 * print name and link info for hard and soft links
152 */
153 (void)fputs(f_date, fp);
154 (void)putc(' ', fp);
155 safe_print(arcn->name, fp);
156 if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) {
157 fputs(" == ", fp);
158 safe_print(arcn->ln_name, fp);
159 } else if (arcn->type == PAX_SLK) {
160 fputs(" => ", fp);
161 safe_print(arcn->ln_name, fp);
162 }
163 (void)putc(term, fp);
164 (void)fflush(fp);
165 return;
166}
167
168/*
169 * tty_ls()
170 * print a short summary of file to tty.
171 */
172
173void
174ls_tty(ARCHD *arcn)
175{
176 char f_date[DATELEN];
177 char f_mode[MODELEN];
178 const char *timefrmt;
179
180 if (ltmfrmt == NULL) {
181 /*
182 * no locale specified format
183 */
184 if ((arcn->sb.st_mtime + SIXMONTHS) <= time(NULL))
185 timefrmt = OLDFRMT;
186 else
187 timefrmt = CURFRMT;
188 } else
189 timefrmt = ltmfrmt;
190
191 /*
192 * convert time to string, and print
193 */
194 if (strftime(f_date, DATELEN, timefrmt,
195 localtime(&(arcn->sb.st_mtime))) == 0)
196 f_date[0] = '\0';
197 strmode(arcn->sb.st_mode, f_mode);
198 tty_prnt("%s%s %s\n", f_mode, f_date, arcn->name);
199 return;
200}
201
202void
203safe_print(const char *str, FILE *fp)
204{
205#ifndef __GLIBC__
206 char visbuf[5];
207 const char *cp;
208
209 /*
210 * if printing to a tty, use vis(3) to print special characters.
211 */
212 if (isatty(fileno(fp))) {
213 for (cp = str; *cp; cp++) {
214 (void)vis(visbuf, cp[0], VIS_CSTYLE, cp[1]);
215 (void)fputs(visbuf, fp);
216 }
217 } else
218#endif
219 (void)fputs(str, fp);
220}
221
222/*
223 * asc_ul()
224 * convert hex/octal character string into a u_long. We do not have to
225 * check for overflow! (the headers in all supported formats are not large
226 * enough to create an overflow).
227 * NOTE: strings passed to us are NOT TERMINATED.
228 * Return:
229 * unsigned long value
230 */
231
232u_long
233asc_ul(char *str, int len, int base)
234{
235 char *stop;
236 u_long tval = 0;
237
238 stop = str + len;
239
240 /*
241 * skip over leading blanks and zeros
242 */
243 while ((str < stop) && ((*str == ' ') || (*str == '0')))
244 ++str;
245
246 /*
247 * for each valid digit, shift running value (tval) over to next digit
248 * and add next digit
249 */
250 if (base == HEX) {
251 while (str < stop) {
252 if ((*str >= '0') && (*str <= '9'))
253 tval = (tval << 4) + (*str++ - '0');
254 else if ((*str >= 'A') && (*str <= 'F'))
255 tval = (tval << 4) + 10 + (*str++ - 'A');
256 else if ((*str >= 'a') && (*str <= 'f'))
257 tval = (tval << 4) + 10 + (*str++ - 'a');
258 else
259 break;
260 }
261 } else {
262 while ((str < stop) && (*str >= '0') && (*str <= '7'))
263 tval = (tval << 3) + (*str++ - '0');
264 }
265 return(tval);
266}
267
268/*
269 * ul_asc()
270 * convert an unsigned long into an hex/oct ascii string. pads with LEADING
271 * ascii 0's to fill string completely
272 * NOTE: the string created is NOT TERMINATED.
273 */
274
275int
276ul_asc(u_long val, char *str, int len, int base)
277{
278 char *pt;
279 u_long digit;
280
281 /*
282 * WARNING str is not '\0' terminated by this routine
283 */
284 pt = str + len - 1;
285
286 /*
287 * do a tailwise conversion (start at right most end of string to place
288 * least significant digit). Keep shifting until conversion value goes
289 * to zero (all digits were converted)
290 */
291 if (base == HEX) {
292 while (pt >= str) {
293 if ((digit = (val & 0xf)) < 10)
294 *pt-- = '0' + (char)digit;
295 else
296 *pt-- = 'a' + (char)(digit - 10);
297 if ((val = (val >> 4)) == (u_long)0)
298 break;
299 }
300 } else {
301 while (pt >= str) {
302 *pt-- = '0' + (char)(val & 0x7);
303 if ((val = (val >> 3)) == (u_long)0)
304 break;
305 }
306 }
307
308 /*
309 * pad with leading ascii ZEROS. We return -1 if we ran out of space.
310 */
311 while (pt >= str)
312 *pt-- = '0';
313 if (val != (u_long)0)
314 return(-1);
315 return(0);
316}
317
318#ifndef LONG_OFF_T
319/*
320 * asc_uqd()
321 * convert hex/octal character string into a u_quad_t. We do not have to
322 * check for overflow! (the headers in all supported formats are not large
323 * enough to create an overflow).
324 * NOTE: strings passed to us are NOT TERMINATED.
325 * Return:
326 * u_quad_t value
327 */
328
329u_quad_t
330asc_uqd(char *str, int len, int base)
331{
332 char *stop;
333 u_quad_t tval = 0;
334
335 stop = str + len;
336
337 /*
338 * skip over leading blanks and zeros
339 */
340 while ((str < stop) && ((*str == ' ') || (*str == '0')))
341 ++str;
342
343 /*
344 * for each valid digit, shift running value (tval) over to next digit
345 * and add next digit
346 */
347 if (base == HEX) {
348 while (str < stop) {
349 if ((*str >= '0') && (*str <= '9'))
350 tval = (tval << 4) + (*str++ - '0');
351 else if ((*str >= 'A') && (*str <= 'F'))
352 tval = (tval << 4) + 10 + (*str++ - 'A');
353 else if ((*str >= 'a') && (*str <= 'f'))
354 tval = (tval << 4) + 10 + (*str++ - 'a');
355 else
356 break;
357 }
358 } else {
359 while ((str < stop) && (*str >= '0') && (*str <= '7'))
360 tval = (tval << 3) + (*str++ - '0');
361 }
362 return(tval);
363}
364
365/*
366 * uqd_asc()
367 * convert an u_quad_t into a hex/oct ascii string. pads with LEADING
368 * ascii 0's to fill string completely
369 * NOTE: the string created is NOT TERMINATED.
370 */
371
372int
373uqd_asc(u_quad_t val, char *str, int len, int base)
374{
375 char *pt;
376 u_quad_t digit;
377
378 /*
379 * WARNING str is not '\0' terminated by this routine
380 */
381 pt = str + len - 1;
382
383 /*
384 * do a tailwise conversion (start at right most end of string to place
385 * least significant digit). Keep shifting until conversion value goes
386 * to zero (all digits were converted)
387 */
388 if (base == HEX) {
389 while (pt >= str) {
390 if ((digit = (val & 0xf)) < 10)
391 *pt-- = '0' + (char)digit;
392 else
393 *pt-- = 'a' + (char)(digit - 10);
394 if ((val = (val >> 4)) == (u_quad_t)0)
395 break;
396 }
397 } else {
398 while (pt >= str) {
399 *pt-- = '0' + (char)(val & 0x7);
400 if ((val = (val >> 3)) == (u_quad_t)0)
401 break;
402 }
403 }
404
405 /*
406 * pad with leading ascii ZEROS. We return -1 if we ran out of space.
407 */
408 while (pt >= str)
409 *pt-- = '0';
410 if (val != (u_quad_t)0)
411 return(-1);
412 return(0);
413}
414#endif
415
416/*
417 * Copy at max min(bufz, fieldsz) chars from field to buf, stopping
418 * at the first NUL char. NUL terminate buf if there is room left.
419 */
420size_t
421fieldcpy(char *buf, size_t bufsz, const char *field, size_t fieldsz)
422{
423 char *p = buf;
424 const char *q = field;
425 size_t i = 0;
426
427 if (fieldsz > bufsz)
428 fieldsz = bufsz;
429 while (i < fieldsz && *q != '\0') {
430 *p++ = *q++;
431 i++;
432 }
433 if (i < bufsz)
434 *p = '\0';
435 return(i);
436}
Note: See TracBrowser for help on using the repository browser.