168349Sobrien/* 2133359Sobrien * Copyright (c) Ian F. Darwin 1986-1995. 3133359Sobrien * Software written by Ian F. Darwin and others; 4133359Sobrien * maintained 1995-present by Christos Zoulas and others. 5191736Sobrien * 6133359Sobrien * Redistribution and use in source and binary forms, with or without 7133359Sobrien * modification, are permitted provided that the following conditions 8133359Sobrien * are met: 9133359Sobrien * 1. Redistributions of source code must retain the above copyright 10133359Sobrien * notice immediately at the beginning of the file, without modification, 11133359Sobrien * this list of conditions, and the following disclaimer. 12133359Sobrien * 2. Redistributions in binary form must reproduce the above copyright 13133359Sobrien * notice, this list of conditions and the following disclaimer in the 14133359Sobrien * documentation and/or other materials provided with the distribution. 15191736Sobrien * 16133359Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17133359Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18133359Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19133359Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 20133359Sobrien * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21133359Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22133359Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23133359Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24133359Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25133359Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26133359Sobrien * SUCH DAMAGE. 27133359Sobrien */ 28133359Sobrien/* 2968349Sobrien * file - find type of a file or files - main program. 3068349Sobrien */ 31103373Sobrien 32103373Sobrien#include "file.h" 33191736Sobrien 34191736Sobrien#ifndef lint 35309848SdelphijFILE_RCSID("@(#)$File: file.c,v 1.172 2016/10/24 15:21:07 christos Exp $") 36191736Sobrien#endif /* lint */ 37191736Sobrien 38133359Sobrien#include "magic.h" 39133359Sobrien 4068349Sobrien#include <stdlib.h> 4169216Sobrien#include <unistd.h> 4268349Sobrien#include <string.h> 4368349Sobrien#ifdef RESTORE_TIME 4468349Sobrien# if (__COHERENT__ >= 0x420) 4568349Sobrien# include <sys/utime.h> 4668349Sobrien# else 4768349Sobrien# ifdef USE_UTIMES 4868349Sobrien# include <sys/time.h> 4968349Sobrien# else 5068349Sobrien# include <utime.h> 5168349Sobrien# endif 5268349Sobrien# endif 5368349Sobrien#endif 5468349Sobrien#ifdef HAVE_UNISTD_H 5568349Sobrien#include <unistd.h> /* for read() */ 5668349Sobrien#endif 57133359Sobrien#ifdef HAVE_WCHAR_H 58133359Sobrien#include <wchar.h> 59133359Sobrien#endif 6068349Sobrien 61192348Sdelphij#if defined(HAVE_GETOPT_H) && defined(HAVE_STRUCT_OPTION) 62186690Sobrien#include <getopt.h> 63226048Sobrien#ifndef HAVE_GETOPT_LONG 64226048Sobrienint getopt_long(int argc, char * const *argv, const char *optstring, const struct option *longopts, int *longindex); 65226048Sobrien#endif 66133359Sobrien#else 67186690Sobrien#include "mygetopt.h" 68103373Sobrien#endif 69103373Sobrien 7068349Sobrien#ifdef S_IFLNK 71284778Sdelphij#define FILE_FLAGS "-bcEhikLlNnprsvzZ0" 7268349Sobrien#else 73284778Sdelphij#define FILE_FLAGS "-bcEiklNnprsvzZ0" 7468349Sobrien#endif 7568349Sobrien 76226048Sobrien# define USAGE \ 77226048Sobrien "Usage: %s [" FILE_FLAGS \ 78284778Sdelphij "] [--apple] [--extension] [--mime-encoding] [--mime-type]\n" \ 79226048Sobrien " [-e testname] [-F separator] [-f namefile] [-m magicfiles] " \ 80226048Sobrien "file ...\n" \ 81226048Sobrien " %s -C [-m magicfiles]\n" \ 82226048Sobrien " %s [--help]\n" 83103373Sobrien 84133359Sobrienprivate int /* Global command-line options */ 8568349Sobrien bflag = 0, /* brief output format */ 86110949Sobrien nopad = 0, /* Don't pad output */ 87169942Sobrien nobuffer = 0, /* Do not buffer stdout */ 88169942Sobrien nulsep = 0; /* Append '\0' to the separator */ 8968349Sobrien 90159764Sobrienprivate const char *separator = ":"; /* Default field separator */ 91191736Sobrienprivate const struct option long_options[] = { 92284778Sdelphij#define OPT_HELP 1 93284778Sdelphij#define OPT_APPLE 2 94284778Sdelphij#define OPT_EXTENSIONS 3 95284778Sdelphij#define OPT_MIME_TYPE 4 96284778Sdelphij#define OPT_MIME_ENCODING 5 97300899Sdelphij#define OPT(shortname, longname, opt, def, doc) \ 98191736Sobrien {longname, opt, NULL, shortname}, 99300899Sdelphij#define OPT_LONGONLY(longname, opt, def, doc, id) \ 100284778Sdelphij {longname, opt, NULL, id}, 101191736Sobrien#include "file_opts.h" 102191736Sobrien#undef OPT 103191736Sobrien#undef OPT_LONGONLY 104191736Sobrien {0, 0, NULL, 0} 105191736Sobrien}; 106284778Sdelphij#define OPTSTRING "bcCde:Ef:F:hiklLm:nNpP:rsvzZ0" 10768349Sobrien 108191736Sobrienprivate const struct { 109191736Sobrien const char *name; 110191736Sobrien int value; 111191736Sobrien} nv[] = { 112191736Sobrien { "apptype", MAGIC_NO_CHECK_APPTYPE }, 113191736Sobrien { "ascii", MAGIC_NO_CHECK_ASCII }, 114191736Sobrien { "cdf", MAGIC_NO_CHECK_CDF }, 115191736Sobrien { "compress", MAGIC_NO_CHECK_COMPRESS }, 116191736Sobrien { "elf", MAGIC_NO_CHECK_ELF }, 117191736Sobrien { "encoding", MAGIC_NO_CHECK_ENCODING }, 118191736Sobrien { "soft", MAGIC_NO_CHECK_SOFT }, 119191736Sobrien { "tar", MAGIC_NO_CHECK_TAR }, 120226048Sobrien { "text", MAGIC_NO_CHECK_TEXT }, /* synonym for ascii */ 121234250Sobrien { "tokens", MAGIC_NO_CHECK_TOKENS }, /* OBSOLETE: ignored for backwards compatibility */ 122191736Sobrien}; 123191736Sobrien 124276415Sdelphijprivate struct { 125276415Sdelphij const char *name; 126276415Sdelphij int tag; 127276415Sdelphij size_t value; 128276415Sdelphij} pm[] = { 129276415Sdelphij { "indir", MAGIC_PARAM_INDIR_MAX, 0 }, 130276415Sdelphij { "name", MAGIC_PARAM_NAME_MAX, 0 }, 131276415Sdelphij { "elf_phnum", MAGIC_PARAM_ELF_PHNUM_MAX, 0 }, 132276415Sdelphij { "elf_shnum", MAGIC_PARAM_ELF_SHNUM_MAX, 0 }, 133277592Sdelphij { "elf_notes", MAGIC_PARAM_ELF_NOTES_MAX, 0 }, 134290152Sdelphij { "regex", MAGIC_PARAM_REGEX_MAX, 0 }, 135300899Sdelphij { "bytes", MAGIC_PARAM_BYTES_MAX, 0 }, 136276415Sdelphij}; 137276415Sdelphij 138133359Sobrienprivate char *progname; /* used throughout */ 139300899Sdelphijprivate int posixly; 14068349Sobrien 141284778Sdelphij#ifdef __dead 142284778Sdelphij__dead 143284778Sdelphij#endif 144133359Sobrienprivate void usage(void); 145300899Sdelphijprivate void docprint(const char *, int); 146284778Sdelphij#ifdef __dead 147284778Sdelphij__dead 148284778Sdelphij#endif 149133359Sobrienprivate void help(void); 15068349Sobrien 151191736Sobrienprivate int unwrap(struct magic_set *, const char *); 152191736Sobrienprivate int process(struct magic_set *ms, const char *, int); 153191736Sobrienprivate struct magic_set *load(const char *, int); 154276415Sdelphijprivate void setparam(const char *); 155276415Sdelphijprivate void applyparam(magic_t); 156133359Sobrien 157191736Sobrien 15868349Sobrien/* 15968349Sobrien * main - parse arguments and handle options 16068349Sobrien */ 16168349Sobrienint 162133359Sobrienmain(int argc, char *argv[]) 16368349Sobrien{ 164175296Sobrien int c; 165175296Sobrien size_t i; 166133359Sobrien int action = 0, didsomefiles = 0, errflg = 0; 167191736Sobrien int flags = 0, e = 0; 168191736Sobrien struct magic_set *magic = NULL; 169103373Sobrien int longindex; 170226048Sobrien const char *magicfile = NULL; /* where the magic is */ 17168349Sobrien 172159764Sobrien /* makes islower etc work for other langs */ 173276415Sdelphij#ifdef HAVE_SETLOCALE 174159764Sobrien (void)setlocale(LC_CTYPE, ""); 175276415Sdelphij#endif 17668349Sobrien 177103373Sobrien#ifdef __EMX__ 178103373Sobrien /* sh-like wildcard expansion! Shouldn't hurt at least ... */ 179103373Sobrien _wildcard(&argc, &argv); 180103373Sobrien#endif 181103373Sobrien 18268349Sobrien if ((progname = strrchr(argv[0], '/')) != NULL) 18368349Sobrien progname++; 18468349Sobrien else 18568349Sobrien progname = argv[0]; 18668349Sobrien 187159764Sobrien#ifdef S_IFLNK 188300899Sdelphij posixly = getenv("POSIXLY_CORRECT") != NULL; 189300899Sdelphij flags |= posixly ? MAGIC_SYMLINK : 0; 190159764Sobrien#endif 191103373Sobrien while ((c = getopt_long(argc, argv, OPTSTRING, long_options, 192103373Sobrien &longindex)) != -1) 19368349Sobrien switch (c) { 194284778Sdelphij case OPT_HELP: 195284778Sdelphij help(); 196103373Sobrien break; 197284778Sdelphij case OPT_APPLE: 198284778Sdelphij flags |= MAGIC_APPLE; 199284778Sdelphij break; 200284778Sdelphij case OPT_EXTENSIONS: 201284778Sdelphij flags |= MAGIC_EXTENSION; 202284778Sdelphij break; 203284778Sdelphij case OPT_MIME_TYPE: 204284778Sdelphij flags |= MAGIC_MIME_TYPE; 205284778Sdelphij break; 206284778Sdelphij case OPT_MIME_ENCODING: 207284778Sdelphij flags |= MAGIC_MIME_ENCODING; 208284778Sdelphij break; 209169942Sobrien case '0': 210300899Sdelphij nulsep++; 211169942Sobrien break; 21268349Sobrien case 'b': 213175296Sobrien bflag++; 21468349Sobrien break; 21568349Sobrien case 'c': 216133359Sobrien action = FILE_CHECK; 21768349Sobrien break; 21874784Sobrien case 'C': 219133359Sobrien action = FILE_COMPILE; 22074784Sobrien break; 22168349Sobrien case 'd': 222133359Sobrien flags |= MAGIC_DEBUG|MAGIC_CHECK; 22368349Sobrien break; 224267843Sdelphij case 'E': 225267843Sdelphij flags |= MAGIC_ERROR; 226267843Sdelphij break; 227169962Sobrien case 'e': 228169962Sobrien for (i = 0; i < sizeof(nv) / sizeof(nv[0]); i++) 229169962Sobrien if (strcmp(nv[i].name, optarg) == 0) 230169962Sobrien break; 231169962Sobrien 232169962Sobrien if (i == sizeof(nv) / sizeof(nv[0])) 233169962Sobrien errflg++; 234169962Sobrien else 235169962Sobrien flags |= nv[i].value; 236169962Sobrien break; 237191736Sobrien 23868349Sobrien case 'f': 239133359Sobrien if(action) 240133359Sobrien usage(); 241191736Sobrien if (magic == NULL) 242191736Sobrien if ((magic = load(magicfile, flags)) == NULL) 243191736Sobrien return 1; 244290152Sdelphij applyparam(magic); 245191736Sobrien e |= unwrap(magic, optarg); 24668349Sobrien ++didsomefiles; 24768349Sobrien break; 248110949Sobrien case 'F': 249133359Sobrien separator = optarg; 250110949Sobrien break; 25168349Sobrien case 'i': 252133359Sobrien flags |= MAGIC_MIME; 25368349Sobrien break; 25468349Sobrien case 'k': 255133359Sobrien flags |= MAGIC_CONTINUE; 25668349Sobrien break; 257226048Sobrien case 'l': 258226048Sobrien action = FILE_LIST; 259226048Sobrien break; 26068349Sobrien case 'm': 26168349Sobrien magicfile = optarg; 26268349Sobrien break; 26368349Sobrien case 'n': 26468349Sobrien ++nobuffer; 26568349Sobrien break; 266110949Sobrien case 'N': 267110949Sobrien ++nopad; 268110949Sobrien break; 269133359Sobrien#if defined(HAVE_UTIME) || defined(HAVE_UTIMES) 270133359Sobrien case 'p': 271133359Sobrien flags |= MAGIC_PRESERVE_ATIME; 272133359Sobrien break; 273133359Sobrien#endif 274276415Sdelphij case 'P': 275276415Sdelphij setparam(optarg); 276276415Sdelphij break; 277133359Sobrien case 'r': 278133359Sobrien flags |= MAGIC_RAW; 279133359Sobrien break; 28068349Sobrien case 's': 281133359Sobrien flags |= MAGIC_DEVICES; 28268349Sobrien break; 28368349Sobrien case 'v': 284226048Sobrien if (magicfile == NULL) 285226048Sobrien magicfile = magic_getpath(magicfile, action); 286226048Sobrien (void)fprintf(stdout, "%s-%s\n", progname, VERSION); 287226048Sobrien (void)fprintf(stdout, "magic file from %s\n", 28868349Sobrien magicfile); 289267843Sdelphij return 0; 29068349Sobrien case 'z': 291133359Sobrien flags |= MAGIC_COMPRESS; 29268349Sobrien break; 293284778Sdelphij 294284778Sdelphij case 'Z': 295284778Sdelphij flags |= MAGIC_COMPRESS|MAGIC_COMPRESS_TRANSP; 296284778Sdelphij break; 29768349Sobrien#ifdef S_IFLNK 29868349Sobrien case 'L': 299133359Sobrien flags |= MAGIC_SYMLINK; 30068349Sobrien break; 301159764Sobrien case 'h': 302159764Sobrien flags &= ~MAGIC_SYMLINK; 303159764Sobrien break; 30468349Sobrien#endif 30568349Sobrien case '?': 30668349Sobrien default: 30768349Sobrien errflg++; 30868349Sobrien break; 30968349Sobrien } 31068349Sobrien 31168349Sobrien if (errflg) { 31274784Sobrien usage(); 31368349Sobrien } 314191736Sobrien if (e) 315191736Sobrien return e; 31668349Sobrien 317267843Sdelphij if (MAGIC_VERSION != magic_version()) 318267843Sdelphij (void)fprintf(stderr, "%s: compiled magic version [%d] " 319267843Sdelphij "does not match with shared library magic version [%d]\n", 320267843Sdelphij progname, MAGIC_VERSION, magic_version()); 321267843Sdelphij 322133359Sobrien switch(action) { 323133359Sobrien case FILE_CHECK: 324133359Sobrien case FILE_COMPILE: 325226048Sobrien case FILE_LIST: 326191736Sobrien /* 327191736Sobrien * Don't try to check/compile ~/.magic unless we explicitly 328191736Sobrien * ask for it. 329191736Sobrien */ 330133359Sobrien magic = magic_open(flags|MAGIC_CHECK); 331133359Sobrien if (magic == NULL) { 332133359Sobrien (void)fprintf(stderr, "%s: %s\n", progname, 333133359Sobrien strerror(errno)); 334133359Sobrien return 1; 335133359Sobrien } 336276415Sdelphij 337276415Sdelphij 338226048Sobrien switch(action) { 339226048Sobrien case FILE_CHECK: 340226048Sobrien c = magic_check(magic, magicfile); 341226048Sobrien break; 342226048Sobrien case FILE_COMPILE: 343226048Sobrien c = magic_compile(magic, magicfile); 344226048Sobrien break; 345226048Sobrien case FILE_LIST: 346226048Sobrien c = magic_list(magic, magicfile); 347226048Sobrien break; 348226048Sobrien default: 349226048Sobrien abort(); 350226048Sobrien } 351133359Sobrien if (c == -1) { 352133359Sobrien (void)fprintf(stderr, "%s: %s\n", progname, 353133359Sobrien magic_error(magic)); 354302555Sdelphij e = 1; 355302555Sdelphij goto out; 356133359Sobrien } 357302555Sdelphij goto out; 358133359Sobrien default: 359191736Sobrien if (magic == NULL) 360191736Sobrien if ((magic = load(magicfile, flags)) == NULL) 361191736Sobrien return 1; 362276415Sdelphij applyparam(magic); 36368349Sobrien } 36468349Sobrien 36568349Sobrien if (optind == argc) { 366191736Sobrien if (!didsomefiles) 36774784Sobrien usage(); 36868349Sobrien } 36968349Sobrien else { 370175296Sobrien size_t j, wid, nw; 371175296Sobrien for (wid = 0, j = (size_t)optind; j < (size_t)argc; j++) { 372175296Sobrien nw = file_mbswidth(argv[j]); 37368349Sobrien if (nw > wid) 37468349Sobrien wid = nw; 37568349Sobrien } 376175296Sobrien /* 377175296Sobrien * If bflag is only set twice, set it depending on 378175296Sobrien * number of files [this is undocumented, and subject to change] 379175296Sobrien */ 380175296Sobrien if (bflag == 2) { 381175296Sobrien bflag = optind >= argc - 1; 382175296Sobrien } 38368349Sobrien for (; optind < argc; optind++) 384191736Sobrien e |= process(magic, argv[optind], wid); 38568349Sobrien } 38668349Sobrien 387302555Sdelphijout: 388191736Sobrien if (magic) 389191736Sobrien magic_close(magic); 390191736Sobrien return e; 39168349Sobrien} 39268349Sobrien 393276415Sdelphijprivate void 394276415Sdelphijapplyparam(magic_t magic) 395276415Sdelphij{ 396276415Sdelphij size_t i; 39768349Sobrien 398276415Sdelphij for (i = 0; i < __arraycount(pm); i++) { 399276415Sdelphij if (pm[i].value == 0) 400276415Sdelphij continue; 401276415Sdelphij if (magic_setparam(magic, pm[i].tag, &pm[i].value) == -1) { 402276415Sdelphij (void)fprintf(stderr, "%s: Can't set %s %s\n", progname, 403276415Sdelphij pm[i].name, strerror(errno)); 404276415Sdelphij exit(1); 405276415Sdelphij } 406276415Sdelphij } 407276415Sdelphij} 408276415Sdelphij 409276415Sdelphijprivate void 410276415Sdelphijsetparam(const char *p) 411276415Sdelphij{ 412276415Sdelphij size_t i; 413276415Sdelphij char *s; 414276415Sdelphij 415276415Sdelphij if ((s = strchr(p, '=')) == NULL) 416276415Sdelphij goto badparm; 417276415Sdelphij 418276415Sdelphij for (i = 0; i < __arraycount(pm); i++) { 419276415Sdelphij if (strncmp(p, pm[i].name, s - p) != 0) 420276415Sdelphij continue; 421276415Sdelphij pm[i].value = atoi(s + 1); 422276415Sdelphij return; 423276415Sdelphij } 424276415Sdelphijbadparm: 425276415Sdelphij (void)fprintf(stderr, "%s: Unknown param %s\n", progname, p); 426276415Sdelphij exit(1); 427276415Sdelphij} 428276415Sdelphij 429191736Sobrienprivate struct magic_set * 430159764Sobrien/*ARGSUSED*/ 431191736Sobrienload(const char *magicfile, int flags) 432133359Sobrien{ 433191736Sobrien struct magic_set *magic = magic_open(flags); 434309848Sdelphij const char *e; 435309848Sdelphij 436133359Sobrien if (magic == NULL) { 437133359Sobrien (void)fprintf(stderr, "%s: %s\n", progname, strerror(errno)); 438191736Sobrien return NULL; 439133359Sobrien } 440133359Sobrien if (magic_load(magic, magicfile) == -1) { 441133359Sobrien (void)fprintf(stderr, "%s: %s\n", 442133359Sobrien progname, magic_error(magic)); 443191736Sobrien magic_close(magic); 444191736Sobrien return NULL; 445133359Sobrien } 446309848Sdelphij if ((e = magic_error(magic)) != NULL) 447309848Sdelphij (void)fprintf(stderr, "%s: Warning: %s\n", progname, e); 448191736Sobrien return magic; 449133359Sobrien} 450133359Sobrien 45168349Sobrien/* 45268349Sobrien * unwrap -- read a file of filenames, do each one. 45368349Sobrien */ 454191736Sobrienprivate int 455191736Sobrienunwrap(struct magic_set *ms, const char *fn) 45668349Sobrien{ 45768349Sobrien FILE *f; 458226048Sobrien ssize_t len; 459226048Sobrien char *line = NULL; 460226048Sobrien size_t llen = 0; 46168349Sobrien int wid = 0, cwid; 462191736Sobrien int e = 0; 46368349Sobrien 46468349Sobrien if (strcmp("-", fn) == 0) { 46568349Sobrien f = stdin; 46668349Sobrien wid = 1; 46768349Sobrien } else { 46868349Sobrien if ((f = fopen(fn, "r")) == NULL) { 469133359Sobrien (void)fprintf(stderr, "%s: Cannot open `%s' (%s).\n", 470133359Sobrien progname, fn, strerror(errno)); 471191736Sobrien return 1; 47268349Sobrien } 47368349Sobrien 474226048Sobrien while ((len = getline(&line, &llen, f)) > 0) { 475226048Sobrien if (line[len - 1] == '\n') 476226048Sobrien line[len - 1] = '\0'; 477226048Sobrien cwid = file_mbswidth(line); 47868349Sobrien if (cwid > wid) 47968349Sobrien wid = cwid; 48068349Sobrien } 48168349Sobrien 48268349Sobrien rewind(f); 48368349Sobrien } 48468349Sobrien 485226048Sobrien while ((len = getline(&line, &llen, f)) > 0) { 486226048Sobrien if (line[len - 1] == '\n') 487226048Sobrien line[len - 1] = '\0'; 488226048Sobrien e |= process(ms, line, wid); 48968349Sobrien if(nobuffer) 490159764Sobrien (void)fflush(stdout); 49168349Sobrien } 49268349Sobrien 493226048Sobrien free(line); 494159764Sobrien (void)fclose(f); 495191736Sobrien return e; 49668349Sobrien} 49768349Sobrien 498169942Sobrien/* 499169942Sobrien * Called for each input file on the command line (or in a list of files) 500169942Sobrien */ 501191736Sobrienprivate int 502191736Sobrienprocess(struct magic_set *ms, const char *inname, int wid) 503133359Sobrien{ 504300899Sdelphij const char *type, c = nulsep > 1 ? '\0' : '\n'; 505133359Sobrien int std_in = strcmp(inname, "-") == 0; 50668349Sobrien 507169942Sobrien if (wid > 0 && !bflag) { 508169942Sobrien (void)printf("%s", std_in ? "/dev/stdin" : inname); 509169942Sobrien if (nulsep) 510169962Sobrien (void)putc('\0', stdout); 511300899Sdelphij if (nulsep < 2) { 512300899Sdelphij (void)printf("%s", separator); 513300899Sdelphij (void)printf("%*s ", 514300899Sdelphij (int) (nopad ? 0 : (wid - file_mbswidth(inname))), 515300899Sdelphij ""); 516300899Sdelphij } 517169942Sobrien } 518133359Sobrien 519191736Sobrien type = magic_file(ms, std_in ? NULL : inname); 520300899Sdelphij 521191736Sobrien if (type == NULL) { 522300899Sdelphij (void)printf("ERROR: %s%c", magic_error(ms), c); 523191736Sobrien return 1; 524191736Sobrien } else { 525300899Sdelphij (void)printf("%s%c", type, c); 526191736Sobrien return 0; 527191736Sobrien } 528133359Sobrien} 529133359Sobrien 530267843Sdelphijprotected size_t 531133359Sobrienfile_mbswidth(const char *s) 53268349Sobrien{ 533133359Sobrien#if defined(HAVE_WCHAR_H) && defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH) 534133359Sobrien size_t bytesconsumed, old_n, n, width = 0; 535133359Sobrien mbstate_t state; 536133359Sobrien wchar_t nextchar; 537133359Sobrien (void)memset(&state, 0, sizeof(mbstate_t)); 538133359Sobrien old_n = n = strlen(s); 53968349Sobrien 540133359Sobrien while (n > 0) { 541133359Sobrien bytesconsumed = mbrtowc(&nextchar, s, n, &state); 542133359Sobrien if (bytesconsumed == (size_t)(-1) || 543133359Sobrien bytesconsumed == (size_t)(-2)) { 544133359Sobrien /* Something went wrong, return something reasonable */ 545133359Sobrien return old_n; 54668349Sobrien } 547133359Sobrien if (s[0] == '\n') { 548133359Sobrien /* 549133359Sobrien * do what strlen() would do, so that caller 550133359Sobrien * is always right 551133359Sobrien */ 552133359Sobrien width++; 553267843Sdelphij } else { 554267843Sdelphij int w = wcwidth(nextchar); 555267843Sdelphij if (w > 0) 556267843Sdelphij width += w; 557267843Sdelphij } 55868349Sobrien 559133359Sobrien s += bytesconsumed, n -= bytesconsumed; 56068349Sobrien } 561133359Sobrien return width; 562133359Sobrien#else 563133359Sobrien return strlen(s); 56468349Sobrien#endif 56568349Sobrien} 56668349Sobrien 567133359Sobrienprivate void 568103373Sobrienusage(void) 56974784Sobrien{ 570226048Sobrien (void)fprintf(stderr, USAGE, progname, progname, progname); 57174784Sobrien exit(1); 57274784Sobrien} 573103373Sobrien 574133359Sobrienprivate void 575300899Sdelphijdefprint(int def) 576267843Sdelphij{ 577300899Sdelphij if (!def) 578300899Sdelphij return; 579300899Sdelphij if (((def & 1) && posixly) || ((def & 2) && !posixly)) 580300899Sdelphij fprintf(stdout, " (default)"); 581300899Sdelphij fputc('\n', stdout); 582300899Sdelphij} 583300899Sdelphij 584300899Sdelphijprivate void 585300899Sdelphijdocprint(const char *opts, int def) 586300899Sdelphij{ 587267843Sdelphij size_t i; 588267843Sdelphij int comma; 589267843Sdelphij char *sp, *p; 590267843Sdelphij 591267843Sdelphij p = strstr(opts, "%o"); 592267843Sdelphij if (p == NULL) { 593267843Sdelphij fprintf(stdout, "%s", opts); 594300899Sdelphij defprint(def); 595267843Sdelphij return; 596267843Sdelphij } 597267843Sdelphij 598267843Sdelphij for (sp = p - 1; sp > opts && *sp == ' '; sp--) 599267843Sdelphij continue; 600267843Sdelphij 601267843Sdelphij fprintf(stdout, "%.*s", (int)(p - opts), opts); 602267843Sdelphij 603267843Sdelphij comma = 0; 604267843Sdelphij for (i = 0; i < __arraycount(nv); i++) { 605267843Sdelphij fprintf(stdout, "%s%s", comma++ ? ", " : "", nv[i].name); 606267843Sdelphij if (i && i % 5 == 0) { 607267843Sdelphij fprintf(stdout, ",\n%*s", (int)(p - sp - 1), ""); 608267843Sdelphij comma = 0; 609267843Sdelphij } 610267843Sdelphij } 611267843Sdelphij 612267843Sdelphij fprintf(stdout, "%s", opts + (p - opts) + 2); 613267843Sdelphij} 614267843Sdelphij 615267843Sdelphijprivate void 616103373Sobrienhelp(void) 617103373Sobrien{ 618175296Sobrien (void)fputs( 619175296Sobrien"Usage: file [OPTION...] [FILE...]\n" 620175296Sobrien"Determine type of FILEs.\n" 621226048Sobrien"\n", stdout); 622300899Sdelphij#define OPT(shortname, longname, opt, def, doc) \ 623267843Sdelphij fprintf(stdout, " -%c, --" longname, shortname), \ 624300899Sdelphij docprint(doc, def); 625300899Sdelphij#define OPT_LONGONLY(longname, opt, def, doc, id) \ 626267843Sdelphij fprintf(stdout, " --" longname), \ 627300899Sdelphij docprint(doc, def); 628175296Sobrien#include "file_opts.h" 629175296Sobrien#undef OPT 630175296Sobrien#undef OPT_LONGONLY 631226048Sobrien fprintf(stdout, "\nReport bugs to http://bugs.gw.com/\n"); 632103373Sobrien exit(0); 633103373Sobrien} 634