1284194Sdelphij/* 2284194Sdelphij * Copyright (c) Ian F. Darwin 1986-1995. 3284194Sdelphij * Software written by Ian F. Darwin and others; 4284194Sdelphij * maintained 1995-present by Christos Zoulas and others. 5284194Sdelphij * 6284194Sdelphij * Redistribution and use in source and binary forms, with or without 7284194Sdelphij * modification, are permitted provided that the following conditions 8284194Sdelphij * are met: 9284194Sdelphij * 1. Redistributions of source code must retain the above copyright 10284194Sdelphij * notice immediately at the beginning of the file, without modification, 11284194Sdelphij * this list of conditions, and the following disclaimer. 12284194Sdelphij * 2. Redistributions in binary form must reproduce the above copyright 13284194Sdelphij * notice, this list of conditions and the following disclaimer in the 14284194Sdelphij * documentation and/or other materials provided with the distribution. 15284194Sdelphij * 16284194Sdelphij * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17284194Sdelphij * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18284194Sdelphij * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19284194Sdelphij * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 20284194Sdelphij * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21284194Sdelphij * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22284194Sdelphij * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23284194Sdelphij * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24284194Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25284194Sdelphij * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26284194Sdelphij * SUCH DAMAGE. 27284194Sdelphij */ 28284194Sdelphij/* 29284194Sdelphij * file - find type of a file or files - main program. 30284194Sdelphij */ 31284194Sdelphij 32284194Sdelphij#include "file.h" 33284194Sdelphij 34284194Sdelphij#ifndef lint 35284194SdelphijFILE_RCSID("@(#)$File: file.c,v 1.160 2014/12/16 23:18:40 christos Exp $") 36284194Sdelphij#endif /* lint */ 37284194Sdelphij 38284194Sdelphij#include "magic.h" 39284194Sdelphij 40284194Sdelphij#include <stdlib.h> 41284194Sdelphij#include <unistd.h> 42284194Sdelphij#include <string.h> 43284194Sdelphij#ifdef RESTORE_TIME 44284194Sdelphij# if (__COHERENT__ >= 0x420) 45284194Sdelphij# include <sys/utime.h> 46284194Sdelphij# else 47284194Sdelphij# ifdef USE_UTIMES 48284194Sdelphij# include <sys/time.h> 49284194Sdelphij# else 50284194Sdelphij# include <utime.h> 51284194Sdelphij# endif 52284194Sdelphij# endif 53284194Sdelphij#endif 54284194Sdelphij#ifdef HAVE_UNISTD_H 55284194Sdelphij#include <unistd.h> /* for read() */ 56284194Sdelphij#endif 57284194Sdelphij#ifdef HAVE_WCHAR_H 58284194Sdelphij#include <wchar.h> 59284194Sdelphij#endif 60284194Sdelphij 61284194Sdelphij#if defined(HAVE_GETOPT_H) && defined(HAVE_STRUCT_OPTION) 62284194Sdelphij#include <getopt.h> 63284194Sdelphij#ifndef HAVE_GETOPT_LONG 64284194Sdelphijint getopt_long(int argc, char * const *argv, const char *optstring, const struct option *longopts, int *longindex); 65284194Sdelphij#endif 66284194Sdelphij#else 67284194Sdelphij#include "mygetopt.h" 68284194Sdelphij#endif 69284194Sdelphij 70284194Sdelphij#ifdef S_IFLNK 71284194Sdelphij#define FILE_FLAGS "-bcEhikLlNnprsvz0" 72284194Sdelphij#else 73284194Sdelphij#define FILE_FLAGS "-bcEiklNnprsvz0" 74284194Sdelphij#endif 75284194Sdelphij 76284194Sdelphij# define USAGE \ 77284194Sdelphij "Usage: %s [" FILE_FLAGS \ 78284194Sdelphij "] [--apple] [--mime-encoding] [--mime-type]\n" \ 79284194Sdelphij " [-e testname] [-F separator] [-f namefile] [-m magicfiles] " \ 80284194Sdelphij "file ...\n" \ 81284194Sdelphij " %s -C [-m magicfiles]\n" \ 82284194Sdelphij " %s [--help]\n" 83284194Sdelphij 84284194Sdelphijprivate int /* Global command-line options */ 85284194Sdelphij bflag = 0, /* brief output format */ 86284194Sdelphij nopad = 0, /* Don't pad output */ 87284194Sdelphij nobuffer = 0, /* Do not buffer stdout */ 88284194Sdelphij nulsep = 0; /* Append '\0' to the separator */ 89284194Sdelphij 90284194Sdelphijprivate const char *separator = ":"; /* Default field separator */ 91284194Sdelphijprivate const struct option long_options[] = { 92284194Sdelphij#define OPT(shortname, longname, opt, doc) \ 93284194Sdelphij {longname, opt, NULL, shortname}, 94284194Sdelphij#define OPT_LONGONLY(longname, opt, doc) \ 95284194Sdelphij {longname, opt, NULL, 0}, 96284194Sdelphij#include "file_opts.h" 97284194Sdelphij#undef OPT 98284194Sdelphij#undef OPT_LONGONLY 99284194Sdelphij {0, 0, NULL, 0} 100284194Sdelphij}; 101284194Sdelphij#define OPTSTRING "bcCde:Ef:F:hiklLm:nNpP:rsvz0" 102284194Sdelphij 103284194Sdelphijprivate const struct { 104284194Sdelphij const char *name; 105284194Sdelphij int value; 106284194Sdelphij} nv[] = { 107284194Sdelphij { "apptype", MAGIC_NO_CHECK_APPTYPE }, 108284194Sdelphij { "ascii", MAGIC_NO_CHECK_ASCII }, 109284194Sdelphij { "cdf", MAGIC_NO_CHECK_CDF }, 110284194Sdelphij { "compress", MAGIC_NO_CHECK_COMPRESS }, 111284194Sdelphij { "elf", MAGIC_NO_CHECK_ELF }, 112284194Sdelphij { "encoding", MAGIC_NO_CHECK_ENCODING }, 113284194Sdelphij { "soft", MAGIC_NO_CHECK_SOFT }, 114284194Sdelphij { "tar", MAGIC_NO_CHECK_TAR }, 115284194Sdelphij { "text", MAGIC_NO_CHECK_TEXT }, /* synonym for ascii */ 116284194Sdelphij { "tokens", MAGIC_NO_CHECK_TOKENS }, /* OBSOLETE: ignored for backwards compatibility */ 117284194Sdelphij}; 118284194Sdelphij 119284194Sdelphijprivate struct { 120284194Sdelphij const char *name; 121284194Sdelphij int tag; 122284194Sdelphij size_t value; 123284194Sdelphij} pm[] = { 124284194Sdelphij { "indir", MAGIC_PARAM_INDIR_MAX, 0 }, 125284194Sdelphij { "name", MAGIC_PARAM_NAME_MAX, 0 }, 126284194Sdelphij { "elf_phnum", MAGIC_PARAM_ELF_PHNUM_MAX, 0 }, 127284194Sdelphij { "elf_shnum", MAGIC_PARAM_ELF_SHNUM_MAX, 0 }, 128284194Sdelphij { "elf_notes", MAGIC_PARAM_ELF_NOTES_MAX, 0 }, 129284194Sdelphij}; 130284194Sdelphij 131284194Sdelphijprivate char *progname; /* used throughout */ 132284194Sdelphij 133284194Sdelphijprivate void usage(void); 134284194Sdelphijprivate void docprint(const char *); 135284194Sdelphijprivate void help(void); 136284194Sdelphij 137284194Sdelphijprivate int unwrap(struct magic_set *, const char *); 138284194Sdelphijprivate int process(struct magic_set *ms, const char *, int); 139284194Sdelphijprivate struct magic_set *load(const char *, int); 140284194Sdelphijprivate void setparam(const char *); 141284194Sdelphijprivate void applyparam(magic_t); 142284194Sdelphij 143284194Sdelphij 144284194Sdelphij/* 145284194Sdelphij * main - parse arguments and handle options 146284194Sdelphij */ 147284194Sdelphijint 148284194Sdelphijmain(int argc, char *argv[]) 149284194Sdelphij{ 150284194Sdelphij int c; 151284194Sdelphij size_t i; 152284194Sdelphij int action = 0, didsomefiles = 0, errflg = 0; 153284194Sdelphij int flags = 0, e = 0; 154284194Sdelphij struct magic_set *magic = NULL; 155284194Sdelphij int longindex; 156284194Sdelphij const char *magicfile = NULL; /* where the magic is */ 157284194Sdelphij 158284194Sdelphij /* makes islower etc work for other langs */ 159284194Sdelphij#ifdef HAVE_SETLOCALE 160284194Sdelphij (void)setlocale(LC_CTYPE, ""); 161284194Sdelphij#endif 162284194Sdelphij 163284194Sdelphij#ifdef __EMX__ 164284194Sdelphij /* sh-like wildcard expansion! Shouldn't hurt at least ... */ 165284194Sdelphij _wildcard(&argc, &argv); 166284194Sdelphij#endif 167284194Sdelphij 168284194Sdelphij if ((progname = strrchr(argv[0], '/')) != NULL) 169284194Sdelphij progname++; 170284194Sdelphij else 171284194Sdelphij progname = argv[0]; 172284194Sdelphij 173284194Sdelphij#ifdef S_IFLNK 174284194Sdelphij flags |= getenv("POSIXLY_CORRECT") ? MAGIC_SYMLINK : 0; 175284194Sdelphij#endif 176284194Sdelphij while ((c = getopt_long(argc, argv, OPTSTRING, long_options, 177284194Sdelphij &longindex)) != -1) 178284194Sdelphij switch (c) { 179284194Sdelphij case 0 : 180284194Sdelphij switch (longindex) { 181284194Sdelphij case 0: 182284194Sdelphij help(); 183284194Sdelphij break; 184284194Sdelphij case 10: 185284194Sdelphij flags |= MAGIC_APPLE; 186284194Sdelphij break; 187284194Sdelphij case 11: 188284194Sdelphij flags |= MAGIC_MIME_TYPE; 189284194Sdelphij break; 190284194Sdelphij case 12: 191284194Sdelphij flags |= MAGIC_MIME_ENCODING; 192284194Sdelphij break; 193284194Sdelphij } 194284194Sdelphij break; 195284194Sdelphij case '0': 196284194Sdelphij nulsep = 1; 197284194Sdelphij break; 198284194Sdelphij case 'b': 199284194Sdelphij bflag++; 200284194Sdelphij break; 201284194Sdelphij case 'c': 202284194Sdelphij action = FILE_CHECK; 203284194Sdelphij break; 204284194Sdelphij case 'C': 205284194Sdelphij action = FILE_COMPILE; 206284194Sdelphij break; 207284194Sdelphij case 'd': 208284194Sdelphij flags |= MAGIC_DEBUG|MAGIC_CHECK; 209284194Sdelphij break; 210284194Sdelphij case 'E': 211284194Sdelphij flags |= MAGIC_ERROR; 212284194Sdelphij break; 213284194Sdelphij case 'e': 214284194Sdelphij for (i = 0; i < sizeof(nv) / sizeof(nv[0]); i++) 215284194Sdelphij if (strcmp(nv[i].name, optarg) == 0) 216284194Sdelphij break; 217284194Sdelphij 218284194Sdelphij if (i == sizeof(nv) / sizeof(nv[0])) 219284194Sdelphij errflg++; 220284194Sdelphij else 221284194Sdelphij flags |= nv[i].value; 222284194Sdelphij break; 223284194Sdelphij 224284194Sdelphij case 'f': 225284194Sdelphij if(action) 226284194Sdelphij usage(); 227284194Sdelphij if (magic == NULL) 228284194Sdelphij if ((magic = load(magicfile, flags)) == NULL) 229284194Sdelphij return 1; 230284194Sdelphij e |= unwrap(magic, optarg); 231284194Sdelphij ++didsomefiles; 232284194Sdelphij break; 233284194Sdelphij case 'F': 234284194Sdelphij separator = optarg; 235284194Sdelphij break; 236284194Sdelphij case 'i': 237284194Sdelphij flags |= MAGIC_MIME; 238284194Sdelphij break; 239284194Sdelphij case 'k': 240284194Sdelphij flags |= MAGIC_CONTINUE; 241284194Sdelphij break; 242284194Sdelphij case 'l': 243284194Sdelphij action = FILE_LIST; 244284194Sdelphij break; 245284194Sdelphij case 'm': 246284194Sdelphij magicfile = optarg; 247284194Sdelphij break; 248284194Sdelphij case 'n': 249284194Sdelphij ++nobuffer; 250284194Sdelphij break; 251284194Sdelphij case 'N': 252284194Sdelphij ++nopad; 253284194Sdelphij break; 254284194Sdelphij#if defined(HAVE_UTIME) || defined(HAVE_UTIMES) 255284194Sdelphij case 'p': 256284194Sdelphij flags |= MAGIC_PRESERVE_ATIME; 257284194Sdelphij break; 258284194Sdelphij#endif 259284194Sdelphij case 'P': 260284194Sdelphij setparam(optarg); 261284194Sdelphij break; 262284194Sdelphij case 'r': 263284194Sdelphij flags |= MAGIC_RAW; 264284194Sdelphij break; 265284194Sdelphij break; 266284194Sdelphij case 's': 267284194Sdelphij flags |= MAGIC_DEVICES; 268284194Sdelphij break; 269284194Sdelphij case 'v': 270284194Sdelphij if (magicfile == NULL) 271284194Sdelphij magicfile = magic_getpath(magicfile, action); 272284194Sdelphij (void)fprintf(stdout, "%s-%s\n", progname, VERSION); 273284194Sdelphij (void)fprintf(stdout, "magic file from %s\n", 274284194Sdelphij magicfile); 275284194Sdelphij return 0; 276284194Sdelphij case 'z': 277284194Sdelphij flags |= MAGIC_COMPRESS; 278284194Sdelphij break; 279284194Sdelphij#ifdef S_IFLNK 280284194Sdelphij case 'L': 281284194Sdelphij flags |= MAGIC_SYMLINK; 282284194Sdelphij break; 283284194Sdelphij case 'h': 284284194Sdelphij flags &= ~MAGIC_SYMLINK; 285284194Sdelphij break; 286284194Sdelphij#endif 287284194Sdelphij case '?': 288284194Sdelphij default: 289284194Sdelphij errflg++; 290284194Sdelphij break; 291284194Sdelphij } 292284194Sdelphij 293284194Sdelphij if (errflg) { 294284194Sdelphij usage(); 295284194Sdelphij } 296284194Sdelphij if (e) 297284194Sdelphij return e; 298284194Sdelphij 299284194Sdelphij if (MAGIC_VERSION != magic_version()) 300284194Sdelphij (void)fprintf(stderr, "%s: compiled magic version [%d] " 301284194Sdelphij "does not match with shared library magic version [%d]\n", 302284194Sdelphij progname, MAGIC_VERSION, magic_version()); 303284194Sdelphij 304284194Sdelphij switch(action) { 305284194Sdelphij case FILE_CHECK: 306284194Sdelphij case FILE_COMPILE: 307284194Sdelphij case FILE_LIST: 308284194Sdelphij /* 309284194Sdelphij * Don't try to check/compile ~/.magic unless we explicitly 310284194Sdelphij * ask for it. 311284194Sdelphij */ 312284194Sdelphij magic = magic_open(flags|MAGIC_CHECK); 313284194Sdelphij if (magic == NULL) { 314284194Sdelphij (void)fprintf(stderr, "%s: %s\n", progname, 315284194Sdelphij strerror(errno)); 316284194Sdelphij return 1; 317284194Sdelphij } 318284194Sdelphij 319284194Sdelphij 320284194Sdelphij switch(action) { 321284194Sdelphij case FILE_CHECK: 322284194Sdelphij c = magic_check(magic, magicfile); 323284194Sdelphij break; 324284194Sdelphij case FILE_COMPILE: 325284194Sdelphij c = magic_compile(magic, magicfile); 326284194Sdelphij break; 327284194Sdelphij case FILE_LIST: 328284194Sdelphij c = magic_list(magic, magicfile); 329284194Sdelphij break; 330284194Sdelphij default: 331284194Sdelphij abort(); 332284194Sdelphij } 333284194Sdelphij if (c == -1) { 334284194Sdelphij (void)fprintf(stderr, "%s: %s\n", progname, 335284194Sdelphij magic_error(magic)); 336284194Sdelphij return 1; 337284194Sdelphij } 338284194Sdelphij return 0; 339284194Sdelphij default: 340284194Sdelphij if (magic == NULL) 341284194Sdelphij if ((magic = load(magicfile, flags)) == NULL) 342284194Sdelphij return 1; 343284194Sdelphij applyparam(magic); 344284194Sdelphij } 345284194Sdelphij 346284194Sdelphij if (optind == argc) { 347284194Sdelphij if (!didsomefiles) 348284194Sdelphij usage(); 349284194Sdelphij } 350284194Sdelphij else { 351284194Sdelphij size_t j, wid, nw; 352284194Sdelphij for (wid = 0, j = (size_t)optind; j < (size_t)argc; j++) { 353284194Sdelphij nw = file_mbswidth(argv[j]); 354284194Sdelphij if (nw > wid) 355284194Sdelphij wid = nw; 356284194Sdelphij } 357284194Sdelphij /* 358284194Sdelphij * If bflag is only set twice, set it depending on 359284194Sdelphij * number of files [this is undocumented, and subject to change] 360284194Sdelphij */ 361284194Sdelphij if (bflag == 2) { 362284194Sdelphij bflag = optind >= argc - 1; 363284194Sdelphij } 364284194Sdelphij for (; optind < argc; optind++) 365284194Sdelphij e |= process(magic, argv[optind], wid); 366284194Sdelphij } 367284194Sdelphij 368284194Sdelphij if (magic) 369284194Sdelphij magic_close(magic); 370284194Sdelphij return e; 371284194Sdelphij} 372284194Sdelphij 373284194Sdelphijprivate void 374284194Sdelphijapplyparam(magic_t magic) 375284194Sdelphij{ 376284194Sdelphij size_t i; 377284194Sdelphij 378284194Sdelphij for (i = 0; i < __arraycount(pm); i++) { 379284194Sdelphij if (pm[i].value == 0) 380284194Sdelphij continue; 381284194Sdelphij if (magic_setparam(magic, pm[i].tag, &pm[i].value) == -1) { 382284194Sdelphij (void)fprintf(stderr, "%s: Can't set %s %s\n", progname, 383284194Sdelphij pm[i].name, strerror(errno)); 384284194Sdelphij exit(1); 385284194Sdelphij } 386284194Sdelphij } 387284194Sdelphij} 388284194Sdelphij 389284194Sdelphijprivate void 390284194Sdelphijsetparam(const char *p) 391284194Sdelphij{ 392284194Sdelphij size_t i; 393284194Sdelphij char *s; 394284194Sdelphij 395284194Sdelphij if ((s = strchr(p, '=')) == NULL) 396284194Sdelphij goto badparm; 397284194Sdelphij 398284194Sdelphij for (i = 0; i < __arraycount(pm); i++) { 399284194Sdelphij if (strncmp(p, pm[i].name, s - p) != 0) 400284194Sdelphij continue; 401284194Sdelphij pm[i].value = atoi(s + 1); 402284194Sdelphij return; 403284194Sdelphij } 404284194Sdelphijbadparm: 405284194Sdelphij (void)fprintf(stderr, "%s: Unknown param %s\n", progname, p); 406284194Sdelphij exit(1); 407284194Sdelphij} 408284194Sdelphij 409284194Sdelphijprivate struct magic_set * 410284194Sdelphij/*ARGSUSED*/ 411284194Sdelphijload(const char *magicfile, int flags) 412284194Sdelphij{ 413284194Sdelphij struct magic_set *magic = magic_open(flags); 414284194Sdelphij if (magic == NULL) { 415284194Sdelphij (void)fprintf(stderr, "%s: %s\n", progname, strerror(errno)); 416284194Sdelphij return NULL; 417284194Sdelphij } 418284194Sdelphij if (magic_load(magic, magicfile) == -1) { 419284194Sdelphij (void)fprintf(stderr, "%s: %s\n", 420284194Sdelphij progname, magic_error(magic)); 421284194Sdelphij magic_close(magic); 422284194Sdelphij return NULL; 423284194Sdelphij } 424284194Sdelphij return magic; 425284194Sdelphij} 426284194Sdelphij 427284194Sdelphij/* 428284194Sdelphij * unwrap -- read a file of filenames, do each one. 429284194Sdelphij */ 430284194Sdelphijprivate int 431284194Sdelphijunwrap(struct magic_set *ms, const char *fn) 432284194Sdelphij{ 433284194Sdelphij FILE *f; 434284194Sdelphij ssize_t len; 435284194Sdelphij char *line = NULL; 436284194Sdelphij size_t llen = 0; 437284194Sdelphij int wid = 0, cwid; 438284194Sdelphij int e = 0; 439284194Sdelphij 440284194Sdelphij if (strcmp("-", fn) == 0) { 441284194Sdelphij f = stdin; 442284194Sdelphij wid = 1; 443284194Sdelphij } else { 444284194Sdelphij if ((f = fopen(fn, "r")) == NULL) { 445284194Sdelphij (void)fprintf(stderr, "%s: Cannot open `%s' (%s).\n", 446284194Sdelphij progname, fn, strerror(errno)); 447284194Sdelphij return 1; 448284194Sdelphij } 449284194Sdelphij 450284194Sdelphij while ((len = getline(&line, &llen, f)) > 0) { 451284194Sdelphij if (line[len - 1] == '\n') 452284194Sdelphij line[len - 1] = '\0'; 453284194Sdelphij cwid = file_mbswidth(line); 454284194Sdelphij if (cwid > wid) 455284194Sdelphij wid = cwid; 456284194Sdelphij } 457284194Sdelphij 458284194Sdelphij rewind(f); 459284194Sdelphij } 460284194Sdelphij 461284194Sdelphij while ((len = getline(&line, &llen, f)) > 0) { 462284194Sdelphij if (line[len - 1] == '\n') 463284194Sdelphij line[len - 1] = '\0'; 464284194Sdelphij e |= process(ms, line, wid); 465284194Sdelphij if(nobuffer) 466284194Sdelphij (void)fflush(stdout); 467284194Sdelphij } 468284194Sdelphij 469284194Sdelphij free(line); 470284194Sdelphij (void)fclose(f); 471284194Sdelphij return e; 472284194Sdelphij} 473284194Sdelphij 474284194Sdelphij/* 475284194Sdelphij * Called for each input file on the command line (or in a list of files) 476284194Sdelphij */ 477284194Sdelphijprivate int 478284194Sdelphijprocess(struct magic_set *ms, const char *inname, int wid) 479284194Sdelphij{ 480284194Sdelphij const char *type; 481284194Sdelphij int std_in = strcmp(inname, "-") == 0; 482284194Sdelphij 483284194Sdelphij if (wid > 0 && !bflag) { 484284194Sdelphij (void)printf("%s", std_in ? "/dev/stdin" : inname); 485284194Sdelphij if (nulsep) 486284194Sdelphij (void)putc('\0', stdout); 487284194Sdelphij (void)printf("%s", separator); 488284194Sdelphij (void)printf("%*s ", 489284194Sdelphij (int) (nopad ? 0 : (wid - file_mbswidth(inname))), ""); 490284194Sdelphij } 491284194Sdelphij 492284194Sdelphij type = magic_file(ms, std_in ? NULL : inname); 493284194Sdelphij if (type == NULL) { 494284194Sdelphij (void)printf("ERROR: %s\n", magic_error(ms)); 495284194Sdelphij return 1; 496284194Sdelphij } else { 497284194Sdelphij (void)printf("%s\n", type); 498284194Sdelphij return 0; 499284194Sdelphij } 500284194Sdelphij} 501284194Sdelphij 502284194Sdelphijprotected size_t 503284194Sdelphijfile_mbswidth(const char *s) 504284194Sdelphij{ 505284194Sdelphij#if defined(HAVE_WCHAR_H) && defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH) 506284194Sdelphij size_t bytesconsumed, old_n, n, width = 0; 507284194Sdelphij mbstate_t state; 508284194Sdelphij wchar_t nextchar; 509284194Sdelphij (void)memset(&state, 0, sizeof(mbstate_t)); 510284194Sdelphij old_n = n = strlen(s); 511284194Sdelphij 512284194Sdelphij while (n > 0) { 513284194Sdelphij bytesconsumed = mbrtowc(&nextchar, s, n, &state); 514284194Sdelphij if (bytesconsumed == (size_t)(-1) || 515284194Sdelphij bytesconsumed == (size_t)(-2)) { 516284194Sdelphij /* Something went wrong, return something reasonable */ 517284194Sdelphij return old_n; 518284194Sdelphij } 519284194Sdelphij if (s[0] == '\n') { 520284194Sdelphij /* 521284194Sdelphij * do what strlen() would do, so that caller 522284194Sdelphij * is always right 523284194Sdelphij */ 524284194Sdelphij width++; 525284194Sdelphij } else { 526284194Sdelphij int w = wcwidth(nextchar); 527284194Sdelphij if (w > 0) 528284194Sdelphij width += w; 529284194Sdelphij } 530284194Sdelphij 531284194Sdelphij s += bytesconsumed, n -= bytesconsumed; 532284194Sdelphij } 533284194Sdelphij return width; 534284194Sdelphij#else 535284194Sdelphij return strlen(s); 536284194Sdelphij#endif 537284194Sdelphij} 538284194Sdelphij 539284194Sdelphijprivate void 540284194Sdelphijusage(void) 541284194Sdelphij{ 542284194Sdelphij (void)fprintf(stderr, USAGE, progname, progname, progname); 543284194Sdelphij exit(1); 544284194Sdelphij} 545284194Sdelphij 546284194Sdelphijprivate void 547284194Sdelphijdocprint(const char *opts) 548284194Sdelphij{ 549284194Sdelphij size_t i; 550284194Sdelphij int comma; 551284194Sdelphij char *sp, *p; 552284194Sdelphij 553284194Sdelphij p = strstr(opts, "%o"); 554284194Sdelphij if (p == NULL) { 555284194Sdelphij fprintf(stdout, "%s", opts); 556284194Sdelphij return; 557284194Sdelphij } 558284194Sdelphij 559284194Sdelphij for (sp = p - 1; sp > opts && *sp == ' '; sp--) 560284194Sdelphij continue; 561284194Sdelphij 562284194Sdelphij fprintf(stdout, "%.*s", (int)(p - opts), opts); 563284194Sdelphij 564284194Sdelphij comma = 0; 565284194Sdelphij for (i = 0; i < __arraycount(nv); i++) { 566284194Sdelphij fprintf(stdout, "%s%s", comma++ ? ", " : "", nv[i].name); 567284194Sdelphij if (i && i % 5 == 0) { 568284194Sdelphij fprintf(stdout, ",\n%*s", (int)(p - sp - 1), ""); 569284194Sdelphij comma = 0; 570284194Sdelphij } 571284194Sdelphij } 572284194Sdelphij 573284194Sdelphij fprintf(stdout, "%s", opts + (p - opts) + 2); 574284194Sdelphij} 575284194Sdelphij 576284194Sdelphijprivate void 577284194Sdelphijhelp(void) 578284194Sdelphij{ 579284194Sdelphij (void)fputs( 580284194Sdelphij"Usage: file [OPTION...] [FILE...]\n" 581284194Sdelphij"Determine type of FILEs.\n" 582284194Sdelphij"\n", stdout); 583284194Sdelphij#define OPT(shortname, longname, opt, doc) \ 584284194Sdelphij fprintf(stdout, " -%c, --" longname, shortname), \ 585284194Sdelphij docprint(doc); 586284194Sdelphij#define OPT_LONGONLY(longname, opt, doc) \ 587284194Sdelphij fprintf(stdout, " --" longname), \ 588284194Sdelphij docprint(doc); 589284194Sdelphij#include "file_opts.h" 590284194Sdelphij#undef OPT 591284194Sdelphij#undef OPT_LONGONLY 592284194Sdelphij fprintf(stdout, "\nReport bugs to http://bugs.gw.com/\n"); 593284194Sdelphij exit(0); 594284194Sdelphij} 595