Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 1 | /* |
| 2 | * finfo - print file info |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 3 | * |
| 4 | * Chet Ramey |
| 5 | * chet@po.cwru.edu |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 6 | */ |
| 7 | |
Chet Ramey | ac50fba | 2014-02-26 09:36:43 -0500 | [diff] [blame] | 8 | /* |
| 9 | Copyright (C) 1999-2009 Free Software Foundation, Inc. |
| 10 | |
| 11 | This file is part of GNU Bash. |
| 12 | Bash is free software: you can redistribute it and/or modify |
| 13 | it under the terms of the GNU General Public License as published by |
| 14 | the Free Software Foundation, either version 3 of the License, or |
| 15 | (at your option) any later version. |
| 16 | |
| 17 | Bash is distributed in the hope that it will be useful, |
| 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 20 | GNU General Public License for more details. |
| 21 | |
| 22 | You should have received a copy of the GNU General Public License |
| 23 | along with Bash. If not, see <http://www.gnu.org/licenses/>. |
| 24 | */ |
| 25 | |
Jari Aalto | 7117c2d | 2002-07-17 14:10:11 +0000 | [diff] [blame] | 26 | #ifdef HAVE_CONFIG_H |
| 27 | # include <config.h> |
| 28 | #endif |
| 29 | |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 30 | #include <sys/types.h> |
| 31 | #include "posixstat.h" |
| 32 | #include <stdio.h> |
| 33 | #include <pwd.h> |
| 34 | #include <grp.h> |
| 35 | #include <errno.h> |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 36 | #include "posixtime.h" |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 37 | |
Jari Aalto | 28ef6c3 | 2001-04-06 19:14:31 +0000 | [diff] [blame] | 38 | #include "bashansi.h" |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 39 | #include "shell.h" |
| 40 | #include "builtins.h" |
| 41 | #include "common.h" |
| 42 | |
| 43 | #ifndef errno |
| 44 | extern int errno; |
| 45 | #endif |
| 46 | |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 47 | extern char **make_builtin_argv (); |
| 48 | |
| 49 | static int printst(); |
| 50 | static int printsome(); |
| 51 | static int printfinfo(); |
| 52 | static int finfo_main(); |
| 53 | |
| 54 | extern int sh_optind; |
| 55 | extern char *sh_optarg; |
| 56 | extern char *this_command_name; |
| 57 | |
| 58 | static char *prog; |
| 59 | static int pmask; |
| 60 | |
| 61 | #define OPT_UID 0x00001 |
| 62 | #define OPT_GID 0x00002 |
| 63 | #define OPT_DEV 0x00004 |
| 64 | #define OPT_INO 0x00008 |
| 65 | #define OPT_PERM 0x00010 |
| 66 | #define OPT_LNKNAM 0x00020 |
| 67 | #define OPT_FID 0x00040 |
| 68 | #define OPT_NLINK 0x00080 |
| 69 | #define OPT_RDEV 0x00100 |
| 70 | #define OPT_SIZE 0x00200 |
| 71 | #define OPT_ATIME 0x00400 |
| 72 | #define OPT_MTIME 0x00800 |
| 73 | #define OPT_CTIME 0x01000 |
| 74 | #define OPT_BLKSIZE 0x02000 |
| 75 | #define OPT_BLKS 0x04000 |
| 76 | #define OPT_FTYPE 0x08000 |
| 77 | #define OPT_PMASK 0x10000 |
| 78 | #define OPT_OPERM 0x20000 |
| 79 | |
| 80 | #define OPT_ASCII 0x1000000 |
| 81 | |
| 82 | #define OPTIONS "acdgiflmnopsuACGMP:U" |
| 83 | |
| 84 | static int |
| 85 | octal(s) |
| 86 | char *s; |
| 87 | { |
| 88 | int r; |
| 89 | |
| 90 | r = *s - '0'; |
| 91 | while (*++s >= '0' && *s <= '7') |
| 92 | r = (r * 8) + (*s - '0'); |
| 93 | return r; |
| 94 | } |
| 95 | |
| 96 | static int |
| 97 | finfo_main(argc, argv) |
| 98 | int argc; |
| 99 | char **argv; |
| 100 | { |
| 101 | register int i; |
| 102 | int mode, flags, opt; |
| 103 | |
| 104 | sh_optind = 0; /* XXX */ |
| 105 | prog = base_pathname(argv[0]); |
| 106 | if (argc == 1) { |
| 107 | builtin_usage(); |
| 108 | return(1); |
| 109 | } |
| 110 | flags = 0; |
| 111 | while ((opt = sh_getopt(argc, argv, OPTIONS)) != EOF) { |
| 112 | switch(opt) { |
| 113 | case 'a': flags |= OPT_ATIME; break; |
| 114 | case 'A': flags |= OPT_ATIME|OPT_ASCII; break; |
| 115 | case 'c': flags |= OPT_CTIME; break; |
| 116 | case 'C': flags |= OPT_CTIME|OPT_ASCII; break; |
| 117 | case 'd': flags |= OPT_DEV; break; |
| 118 | case 'i': flags |= OPT_INO; break; |
| 119 | case 'f': flags |= OPT_FID; break; |
| 120 | case 'g': flags |= OPT_GID; break; |
| 121 | case 'G': flags |= OPT_GID|OPT_ASCII; break; |
| 122 | case 'l': flags |= OPT_LNKNAM; break; |
| 123 | case 'm': flags |= OPT_MTIME; break; |
| 124 | case 'M': flags |= OPT_MTIME|OPT_ASCII; break; |
| 125 | case 'n': flags |= OPT_NLINK; break; |
| 126 | case 'o': flags |= OPT_OPERM; break; |
| 127 | case 'p': flags |= OPT_PERM; break; |
| 128 | case 'P': flags |= OPT_PMASK; pmask = octal(sh_optarg); break; |
| 129 | case 's': flags |= OPT_SIZE; break; |
| 130 | case 'u': flags |= OPT_UID; break; |
| 131 | case 'U': flags |= OPT_UID|OPT_ASCII; break; |
| 132 | default: builtin_usage (); return(1); |
| 133 | } |
| 134 | } |
| 135 | |
| 136 | argc -= sh_optind; |
| 137 | argv += sh_optind; |
| 138 | |
| 139 | if (argc == 0) { |
| 140 | builtin_usage(); |
| 141 | return(1); |
| 142 | } |
| 143 | |
| 144 | for (i = 0; i < argc; i++) |
| 145 | opt = flags ? printsome (argv[i], flags) : printfinfo(argv[i]); |
| 146 | |
| 147 | return(opt); |
| 148 | } |
| 149 | |
| 150 | static struct stat * |
| 151 | getstat(f) |
| 152 | char *f; |
| 153 | { |
| 154 | static struct stat st; |
| 155 | int fd, r; |
Jari Aalto | 7117c2d | 2002-07-17 14:10:11 +0000 | [diff] [blame] | 156 | intmax_t lfd; |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 157 | |
| 158 | if (strncmp(f, "/dev/fd/", 8) == 0) { |
Jari Aalto | 7117c2d | 2002-07-17 14:10:11 +0000 | [diff] [blame] | 159 | if ((legal_number(f + 8, &lfd) == 0) || (int)lfd != lfd) { |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 160 | builtin_error("%s: invalid fd", f + 8); |
| 161 | return ((struct stat *)0); |
| 162 | } |
| 163 | fd = lfd; |
| 164 | r = fstat(fd, &st); |
| 165 | } else |
Jari Aalto | 28ef6c3 | 2001-04-06 19:14:31 +0000 | [diff] [blame] | 166 | #ifdef HAVE_LSTAT |
| 167 | r = lstat(f, &st); |
| 168 | #else |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 169 | r = stat(f, &st); |
Jari Aalto | 28ef6c3 | 2001-04-06 19:14:31 +0000 | [diff] [blame] | 170 | #endif |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 171 | if (r < 0) { |
| 172 | builtin_error("%s: cannot stat: %s", f, strerror(errno)); |
| 173 | return ((struct stat *)0); |
| 174 | } |
| 175 | return (&st); |
| 176 | } |
| 177 | |
| 178 | static int |
| 179 | printfinfo(f) |
| 180 | char *f; |
| 181 | { |
| 182 | struct stat *st; |
| 183 | |
| 184 | st = getstat(f); |
| 185 | return (st ? printst(st) : 1); |
| 186 | } |
| 187 | |
| 188 | static int |
| 189 | getperm(m) |
| 190 | int m; |
| 191 | { |
| 192 | return (m & (S_IRWXU|S_IRWXG|S_IRWXO|S_ISUID|S_ISGID)); |
| 193 | } |
| 194 | |
| 195 | static int |
| 196 | perms(m) |
| 197 | int m; |
| 198 | { |
| 199 | char ubits[4], gbits[4], obits[4]; /* u=rwx,g=rwx,o=rwx */ |
| 200 | int i; |
| 201 | |
| 202 | i = 0; |
| 203 | if (m & S_IRUSR) |
| 204 | ubits[i++] = 'r'; |
| 205 | if (m & S_IWUSR) |
| 206 | ubits[i++] = 'w'; |
| 207 | if (m & S_IXUSR) |
| 208 | ubits[i++] = 'x'; |
| 209 | ubits[i] = '\0'; |
| 210 | |
| 211 | i = 0; |
| 212 | if (m & S_IRGRP) |
| 213 | gbits[i++] = 'r'; |
| 214 | if (m & S_IWGRP) |
| 215 | gbits[i++] = 'w'; |
| 216 | if (m & S_IXGRP) |
| 217 | gbits[i++] = 'x'; |
| 218 | gbits[i] = '\0'; |
| 219 | |
| 220 | i = 0; |
| 221 | if (m & S_IROTH) |
| 222 | obits[i++] = 'r'; |
| 223 | if (m & S_IWOTH) |
| 224 | obits[i++] = 'w'; |
| 225 | if (m & S_IXOTH) |
| 226 | obits[i++] = 'x'; |
| 227 | obits[i] = '\0'; |
| 228 | |
Jari Aalto | b72432f | 1999-02-19 17:11:39 +0000 | [diff] [blame] | 229 | if (m & S_ISUID) |
| 230 | ubits[2] = (m & S_IXUSR) ? 's' : 'S'; |
| 231 | if (m & S_ISGID) |
| 232 | gbits[2] = (m & S_IXGRP) ? 's' : 'S'; |
| 233 | if (m & S_ISVTX) |
| 234 | obits[2] = (m & S_IXOTH) ? 't' : 'T'; |
| 235 | |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 236 | printf ("u=%s,g=%s,o=%s", ubits, gbits, obits); |
| 237 | } |
| 238 | |
| 239 | static int |
| 240 | printmode(mode) |
| 241 | int mode; |
| 242 | { |
| 243 | if (S_ISBLK(mode)) |
| 244 | printf("S_IFBLK "); |
| 245 | if (S_ISCHR(mode)) |
| 246 | printf("S_IFCHR "); |
| 247 | if (S_ISDIR(mode)) |
| 248 | printf("S_IFDIR "); |
| 249 | if (S_ISREG(mode)) |
| 250 | printf("S_IFREG "); |
| 251 | if (S_ISFIFO(mode)) |
| 252 | printf("S_IFIFO "); |
| 253 | if (S_ISLNK(mode)) |
| 254 | printf("S_IFLNK "); |
| 255 | if (S_ISSOCK(mode)) |
| 256 | printf("S_IFSOCK "); |
Jari Aalto | b72432f | 1999-02-19 17:11:39 +0000 | [diff] [blame] | 257 | #ifdef S_ISWHT |
| 258 | if (S_ISWHT(mode)) |
| 259 | printf("S_ISWHT "); |
| 260 | #endif |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 261 | perms(getperm(mode)); |
| 262 | printf("\n"); |
| 263 | } |
| 264 | |
| 265 | static int |
| 266 | printst(st) |
| 267 | struct stat *st; |
| 268 | { |
| 269 | struct passwd *pw; |
| 270 | struct group *gr; |
| 271 | char *owner; |
Jari Aalto | b80f644 | 2004-07-27 13:29:18 +0000 | [diff] [blame] | 272 | int ma, mi, d; |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 273 | |
Jari Aalto | b80f644 | 2004-07-27 13:29:18 +0000 | [diff] [blame] | 274 | ma = major (st->st_rdev); |
| 275 | mi = minor (st->st_rdev); |
| 276 | #if defined (makedev) |
| 277 | d = makedev (ma, mi); |
| 278 | #else |
| 279 | d = st->st_rdev & 0xFF; |
| 280 | #endif |
| 281 | printf("Device (major/minor): %d (%d/%d)\n", d, ma, mi); |
| 282 | |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 283 | printf("Inode: %d\n", (int) st->st_ino); |
| 284 | printf("Mode: (%o) ", (int) st->st_mode); |
| 285 | printmode((int) st->st_mode); |
| 286 | printf("Link count: %d\n", (int) st->st_nlink); |
| 287 | pw = getpwuid(st->st_uid); |
| 288 | owner = pw ? pw->pw_name : "unknown"; |
| 289 | printf("Uid of owner: %d (%s)\n", (int) st->st_uid, owner); |
| 290 | gr = getgrgid(st->st_gid); |
| 291 | owner = gr ? gr->gr_name : "unknown"; |
| 292 | printf("Gid of owner: %d (%s)\n", (int) st->st_gid, owner); |
| 293 | printf("Device type: %d\n", (int) st->st_rdev); |
| 294 | printf("File size: %ld\n", (long) st->st_size); |
| 295 | printf("File last access time: %s", ctime (&st->st_atime)); |
| 296 | printf("File last modify time: %s", ctime (&st->st_mtime)); |
| 297 | printf("File last status change time: %s", ctime (&st->st_ctime)); |
| 298 | fflush(stdout); |
| 299 | return(0); |
| 300 | } |
| 301 | |
| 302 | static int |
| 303 | printsome(f, flags) |
| 304 | char *f; |
| 305 | int flags; |
| 306 | { |
| 307 | struct stat *st; |
| 308 | struct passwd *pw; |
| 309 | struct group *gr; |
| 310 | int p; |
| 311 | char *b; |
| 312 | |
| 313 | st = getstat(f); |
| 314 | if (st == NULL) |
| 315 | return (1); |
| 316 | |
| 317 | /* Print requested info */ |
| 318 | if (flags & OPT_ATIME) { |
| 319 | if (flags & OPT_ASCII) |
| 320 | printf("%s", ctime(&st->st_atime)); |
| 321 | else |
| 322 | printf("%ld\n", st->st_atime); |
| 323 | } else if (flags & OPT_MTIME) { |
| 324 | if (flags & OPT_ASCII) |
| 325 | printf("%s", ctime(&st->st_mtime)); |
| 326 | else |
| 327 | printf("%ld\n", st->st_mtime); |
| 328 | } else if (flags & OPT_CTIME) { |
| 329 | if (flags & OPT_ASCII) |
| 330 | printf("%s", ctime(&st->st_ctime)); |
| 331 | else |
| 332 | printf("%ld\n", st->st_ctime); |
| 333 | } else if (flags & OPT_DEV) |
| 334 | printf("%d\n", st->st_dev); |
| 335 | else if (flags & OPT_INO) |
| 336 | printf("%d\n", st->st_ino); |
| 337 | else if (flags & OPT_FID) |
| 338 | printf("%d:%ld\n", st->st_dev, st->st_ino); |
| 339 | else if (flags & OPT_NLINK) |
| 340 | printf("%d\n", st->st_nlink); |
| 341 | else if (flags & OPT_LNKNAM) { |
| 342 | #ifdef S_ISLNK |
| 343 | b = xmalloc(4096); |
| 344 | p = readlink(f, b, 4096); |
| 345 | if (p >= 0 && p < 4096) |
| 346 | b[p] = '\0'; |
| 347 | else { |
| 348 | p = errno; |
| 349 | strcpy(b, prog); |
| 350 | strcat(b, ": "); |
| 351 | strcat(b, strerror(p)); |
| 352 | } |
| 353 | printf("%s\n", b); |
| 354 | free(b); |
| 355 | #else |
| 356 | printf("%s\n", f); |
| 357 | #endif |
| 358 | } else if (flags & OPT_PERM) { |
| 359 | perms(st->st_mode); |
| 360 | printf("\n"); |
| 361 | } else if (flags & OPT_OPERM) |
| 362 | printf("%o\n", getperm(st->st_mode)); |
| 363 | else if (flags & OPT_PMASK) |
| 364 | printf("%o\n", getperm(st->st_mode) & pmask); |
| 365 | else if (flags & OPT_UID) { |
| 366 | pw = getpwuid(st->st_uid); |
| 367 | if (flags & OPT_ASCII) |
| 368 | printf("%s\n", pw ? pw->pw_name : "unknown"); |
| 369 | else |
| 370 | printf("%d\n", st->st_uid); |
| 371 | } else if (flags & OPT_GID) { |
| 372 | gr = getgrgid(st->st_gid); |
| 373 | if (flags & OPT_ASCII) |
| 374 | printf("%s\n", gr ? gr->gr_name : "unknown"); |
| 375 | else |
| 376 | printf("%d\n", st->st_gid); |
| 377 | } else if (flags & OPT_SIZE) |
Chet Ramey | 0001803 | 2011-11-21 20:51:19 -0500 | [diff] [blame] | 378 | printf("%ld\n", (long) st->st_size); |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 379 | |
| 380 | return (0); |
| 381 | } |
| 382 | |
| 383 | #ifndef NOBUILTIN |
Jari Aalto | f73dda0 | 2001-11-13 17:56:06 +0000 | [diff] [blame] | 384 | int |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 385 | finfo_builtin(list) |
| 386 | WORD_LIST *list; |
| 387 | { |
| 388 | int c, r; |
| 389 | char **v; |
| 390 | WORD_LIST *l; |
| 391 | |
| 392 | v = make_builtin_argv (list, &c); |
| 393 | r = finfo_main (c, v); |
| 394 | free (v); |
| 395 | |
| 396 | return r; |
| 397 | } |
| 398 | |
| 399 | static char *finfo_doc[] = { |
Jari Aalto | 3185942 | 2009-01-12 13:36:28 +0000 | [diff] [blame] | 400 | "Display information about file attributes.", |
| 401 | "", |
Jari Aalto | ccc6cda | 1996-12-23 17:02:34 +0000 | [diff] [blame] | 402 | "Display information about each FILE. Only single operators should", |
| 403 | "be supplied. If no options are supplied, a summary of the info", |
| 404 | "available about each FILE is printed. If FILE is of the form", |
| 405 | "/dev/fd/XX, file descriptor XX is described. Operators, if supplied,", |
| 406 | "have the following meanings:", |
| 407 | "", |
| 408 | " -a last file access time", |
| 409 | " -A last file access time in ctime format", |
| 410 | " -c last file status change time", |
| 411 | " -C last file status change time in ctime format", |
| 412 | " -m last file modification time", |
| 413 | " -M last file modification time in ctime format", |
| 414 | " -d device", |
| 415 | " -i inode", |
| 416 | " -f composite file identifier (device:inode)", |
| 417 | " -g gid of owner", |
| 418 | " -G group name of owner", |
| 419 | " -l name of file pointed to by symlink", |
| 420 | " -n link count", |
| 421 | " -o permissions in octal", |
| 422 | " -p permissions in ascii", |
| 423 | " -P mask permissions ANDed with MASK (like with umask)", |
| 424 | " -s file size in bytes", |
| 425 | " -u uid of owner", |
| 426 | " -U user name of owner", |
| 427 | (char *)0 |
| 428 | }; |
| 429 | |
| 430 | struct builtin finfo_struct = { |
| 431 | "finfo", |
| 432 | finfo_builtin, |
| 433 | BUILTIN_ENABLED, |
| 434 | finfo_doc, |
| 435 | "finfo [-acdgiflmnopsuACGMPU] file [file...]", |
| 436 | 0 |
| 437 | }; |
| 438 | #endif |
| 439 | |
| 440 | #ifdef NOBUILTIN |
| 441 | #if defined (PREFER_STDARG) |
| 442 | # include <stdarg.h> |
| 443 | #else |
| 444 | # if defined (PREFER_VARARGS) |
| 445 | # include <varargs.h> |
| 446 | # endif |
| 447 | #endif |
| 448 | |
| 449 | char *this_command_name; |
| 450 | |
| 451 | main(argc, argv) |
| 452 | int argc; |
| 453 | char **argv; |
| 454 | { |
| 455 | this_command_name = argv[0]; |
| 456 | exit(finfo_main(argc, argv)); |
| 457 | } |
| 458 | |
| 459 | void |
| 460 | builtin_usage() |
| 461 | { |
| 462 | fprintf(stderr, "%s: usage: %s [-%s] [file ...]\n", prog, OPTIONS); |
| 463 | } |
| 464 | |
| 465 | #ifndef HAVE_STRERROR |
| 466 | char * |
| 467 | strerror(e) |
| 468 | int e; |
| 469 | { |
| 470 | static char ebuf[40]; |
| 471 | extern int sys_nerr; |
| 472 | extern char *sys_errlist[]; |
| 473 | |
| 474 | if (e < 0 || e > sys_nerr) { |
| 475 | sprintf(ebuf,"Unknown error code %d", e); |
| 476 | return (&ebuf[0]); |
| 477 | } |
| 478 | return (sys_errlist[e]); |
| 479 | } |
| 480 | #endif |
| 481 | |
| 482 | char * |
| 483 | xmalloc(s) |
| 484 | size_t s; |
| 485 | { |
| 486 | char *ret; |
| 487 | extern char *malloc(); |
| 488 | |
| 489 | ret = malloc(s); |
| 490 | if (ret) |
| 491 | return (ret); |
| 492 | fprintf(stderr, "%s: cannot malloc %d bytes\n", prog, s); |
| 493 | exit(1); |
| 494 | } |
| 495 | |
| 496 | char * |
| 497 | base_pathname(p) |
| 498 | char *p; |
| 499 | { |
| 500 | char *t; |
| 501 | |
| 502 | if (t = strrchr(p, '/')) |
| 503 | return(++t); |
| 504 | return(p); |
| 505 | } |
| 506 | |
| 507 | int |
| 508 | legal_number (string, result) |
| 509 | char *string; |
| 510 | long *result; |
| 511 | { |
| 512 | int sign; |
| 513 | long value; |
| 514 | |
| 515 | sign = 1; |
| 516 | value = 0; |
| 517 | |
| 518 | if (result) |
| 519 | *result = 0; |
| 520 | |
| 521 | /* Skip leading whitespace characters. */ |
| 522 | while (whitespace (*string)) |
| 523 | string++; |
| 524 | |
| 525 | if (!*string) |
| 526 | return (0); |
| 527 | |
| 528 | /* We allow leading `-' or `+'. */ |
| 529 | if (*string == '-' || *string == '+') |
| 530 | { |
| 531 | if (!digit (string[1])) |
| 532 | return (0); |
| 533 | |
| 534 | if (*string == '-') |
| 535 | sign = -1; |
| 536 | |
| 537 | string++; |
| 538 | } |
| 539 | |
| 540 | while (digit (*string)) |
| 541 | { |
| 542 | if (result) |
| 543 | value = (value * 10) + digit_value (*string); |
| 544 | string++; |
| 545 | } |
| 546 | |
| 547 | /* Skip trailing whitespace, if any. */ |
| 548 | while (whitespace (*string)) |
| 549 | string++; |
| 550 | |
| 551 | /* Error if not at end of string. */ |
| 552 | if (*string) |
| 553 | return (0); |
| 554 | |
| 555 | if (result) |
| 556 | *result = value * sign; |
| 557 | |
| 558 | return (1); |
| 559 | } |
| 560 | |
| 561 | int sh_optind; |
| 562 | char *sh_optarg; |
| 563 | int sh_opterr; |
| 564 | |
| 565 | extern int optind; |
| 566 | extern char *optarg; |
| 567 | |
| 568 | int |
| 569 | sh_getopt(c, v, o) |
| 570 | int c; |
| 571 | char **v, *o; |
| 572 | { |
| 573 | int r; |
| 574 | |
| 575 | r = getopt(c, v, o); |
| 576 | sh_optind = optind; |
| 577 | sh_optarg = optarg; |
| 578 | return r; |
| 579 | } |
| 580 | |
| 581 | #if defined (USE_VARARGS) |
| 582 | void |
| 583 | #if defined (PREFER_STDARG) |
| 584 | builtin_error (const char *format, ...) |
| 585 | #else |
| 586 | builtin_error (format, va_alist) |
| 587 | const char *format; |
| 588 | va_dcl |
| 589 | #endif |
| 590 | { |
| 591 | va_list args; |
| 592 | |
| 593 | if (this_command_name && *this_command_name) |
| 594 | fprintf (stderr, "%s: ", this_command_name); |
| 595 | |
| 596 | #if defined (PREFER_STDARG) |
| 597 | va_start (args, format); |
| 598 | #else |
| 599 | va_start (args); |
| 600 | #endif |
| 601 | |
| 602 | vfprintf (stderr, format, args); |
| 603 | va_end (args); |
| 604 | fprintf (stderr, "\n"); |
| 605 | } |
| 606 | #else |
| 607 | void |
| 608 | builtin_error (format, arg1, arg2, arg3, arg4, arg5) |
| 609 | char *format, *arg1, *arg2, *arg3, *arg4, *arg5; |
| 610 | { |
| 611 | if (this_command_name && *this_command_name) |
| 612 | fprintf (stderr, "%s: ", this_command_name); |
| 613 | |
| 614 | fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5); |
| 615 | fprintf (stderr, "\n"); |
| 616 | fflush (stderr); |
| 617 | } |
| 618 | #endif /* !USE_VARARGS */ |
| 619 | |
| 620 | #endif |