/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1989-2012 AT&T Intellectual Property *
* and is licensed under the *
* Eclipse Public License, Version 1.0 *
* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
* *
* Information and Software Systems Research *
* AT&T Research *
* Florham Park NJ *
* *
* Glenn Fowler <gsf@research.att.com> *
* *
***********************************************************************/
#pragma prototyped
/*
* David Korn
* Glenn Fowler
* AT&T Research
*
* rewrite of find program to use fts*() and optget()
* this implementation should have all your favorite
* find options plus these extensions:
*
* -fast pattern
* traverses the fast find database (updatedb(1))
* under the dirs specified on the command line
* for paths that contain pattern; all other
* expression operators apply to matching paths
* -magic pattern
* matches pattern agains the file(1) magic description
* -ignorecase
* case ingnored in path pattern matching
* -xargs command ... \;
* like -exec except that command will be invoked
* with as many file arguments as the system
* allows per command
* -test now
* set the current time to now for testing
*/
static const char usage1[] =
"[-1p1?@(#)$Id: find (AT&T Research) 2012-04-11 $\n]"
"[+NAME?find - find files]"
"[+DESCRIPTION?\bfind\b recursively descends the directory hierarchy for each"
" \apath\a and applies an \aoption\a expression to each file in the"
" hierarchy. \b-print\b is implied if there is no action that"
" generates output. The expression starts with the first argument"
" after the \apath\a arguments. For numeric arguments \an\a, \a+n\a"
" means \a>n\a, \a-n\a means \a<n\a, and \an\a means exactly \an\a.]"
;
static const char usage2[] =
"\n"
"[ path ... ] [ options ]\n"
"\n"
"[+EXIT STATUS?If no commands were executed (\b-exec\b, \b-xargs\b) the exit"
" status is 1 if errors were detected in the directory traversal and"
" 0 if no errors were ecountered. Otherwise the status is:]{"
" [+0?All \acommand\a executions returned exit status 0.]"
" [+1-125?A command line meeting the specified requirements could not"
" be assembled, one or more of the invocations of \acommand\a"
" returned non-0 exit status, or some other error occurred.]"
" [+126?\acommand\a was found but could not be executed.]"
" [+127?\acommand\a was not found.]"
"}"
"[+ENVIRONMENT]{"
" [+FINDCODES?Path name of the \blocate\b(1) database.]"
" [+LOCATE_PATH?Alternate path name of \blocate\b(1) database.]"
"}"
"[+FILES]{"
"}"
"[+NOTES?In order to access the \bslocate\b(1) database the \bfind\b executable"
" must be setgid to the \bslocate\b group.]"
"[+SEE ALSO?\bcpio\b(1), \bfile\b(1), \blocate\b(1), \bls\b(1), \bsh\b(1),"
" \bslocate\b(1), \btest\b(1), \btw\b(1), \bupdatedb\b(1),"
" \bxargs\b(1), \bstat\b(2)]"
;
#include <ast.h>
#include <ls.h>
#include <modex.h>
#include <find.h>
#include <fts.h>
#include <dirent.h>
#include <error.h>
#include <proc.h>
#include <tm.h>
#include <ctype.h>
#include <magic.h>
#include <mime.h>
#include <regex.h>
#include <vmalloc.h>
#include "cmdarg.h"
/*
* this is the list of operations
* retain the order
*/
enum Command
{
};
struct Node_s;
struct State_s;
typedef struct Args_s
{
const char* name;
int type;
int primary;
const char* arg;
const char* values;
const char* help;
} Args_t;
typedef union Value_u
{
char** p;
char* s;
unsigned long u;
long l;
int i;
short h;
char c;
} Value_t;
typedef struct Fmt_s
{
} Fmt_t;
typedef union Item_u
{
char* cp;
unsigned long u;
long l;
int i;
} Item_t;
struct Node_s
{
const char* name;
};
struct State_s
{
unsigned int minlevel;
unsigned int maxlevel;
int walkflags;
char* usage;
unsigned long now;
unsigned long day;
char* codes;
char* fast;
int icase;
int primary;
int reverse;
int silent;
};
/*
* Except for pathnames, these are the only legal arguments
*/
{
"Equivalent to \\(. Begin nested expression.",
"Equivalent to \\). End nested expression.",
"Equivalent to `\\&'. \aexpr1\a \b-and\b \aexpr2\a:"
" Both \aexpr1\a and \aexpr2\a must evaluate \btrue\b."
" This is the default operator for two expression in sequence.",
"File was last accessed \aminutes\a minutes ago.",
"File was last accessed more recently than \afile\a was modified.",
"File was last accessed \adays\a days ago.",
"Turns off \b-silent\b; enables inaccessible file and directory"
" warnings. This is the default.",
"Chop leading \b./\b from printed pathnames.",
"File status changed \aminutes\a minutes ago.",
"File status changed more recently than \afile\a was modified.",
"Sets the \bfind\b or \blocate\b(1) database \apath\a."
" See \bupdatedb\b(1) for a description of this database.",
"Equivalent to `,'. Joins two expressions; the status of the first"
" is ignored.",
"File is written as a binary format \bcpio\b(1) file entry.",
"File status changed \adays\a days ago.",
"Measure times (-amin -atime -cmin -ctime -mmin -mtime) from the"
" beginning of today. The default is 24 hours ago.",
"Process directory contents before the directory itself.",
"A directory with size 0 or with no entries other than . or .., or a"
" regular file with size 0.",
"Execute \acommand ...\a; true if 0 exit status is returned."
" Arguments up to \b;\b are taken as arguments to \acommand\a."
" The string `{}' in \acommand ...\a is globally replaced by "
" the current filename. The command is executed in the directory"
" from which \bfind\b was executed. The second form gathers"
" pathnames until \bARG_MAX\b is reached, replaces {} preceding"
" \b+\b with the list of pathnames, one pathname per argument,"
" and executes \acommand\a ... \apathname\a ..., possibly multiple"
" times, until all pathnames are exhausted.",
"Always false.",
"Searches the \bfind\b or \blocate\b(1) database for paths"
" matching the \bksh\b(1) \apattern\a. See \bupdatedb\b(1) for"
" details on this database. The command line arguments limit"
" the search and the expression, but all depth options are ignored."
" The remainder of the expression is applied to the matching paths.",
"Like -ls except the output is written to \afile\a.",
"Like -print except the output is written to \afile\a.",
"Like -print0 except the output is written to \afile\a.",
"Like -printf except the output is written to \afile\a.",
"Like -printx except the output is written to \afile\a.",
"File is on a filesystem \atype\a. See \bdf\b(1) or"
" \b-printf %F\b for local filesystem type names.",
"File group id name or number matches \aid\a.",
"Ignore case in all pattern match expressions.",
"A case-insensitive version of \b-lname\b \apattern\a.",
"A case-insensitive version of \b-name\b \apattern\a.",
"File has inode number \anumber\a.",
"A case-insensitive version of \b-path\b \apattern\a.",
"A case-insensitive version of \b-regex\b \apattern\a.",
"Current level (depth) is \alevel\a.",
"File has \anumber\a links.",
"File is a symbolic link with text that matches \apattern\a.",
"File is on a local filesystem.",
"Follow symbolic links.",
"List the current file in `ls -dils' format to the standard output.",
"File magic number matches the \bfile\b(1) and \bmagic\b(3)"
" description \apattern\a.",
"Descend at most \alevel\a directory levels below the command"
" line arguments. \b-maxdepth 0\b limits the search to the command"
" line arguments.",
"\b-logical\b for command line arguments, \b-physical\b otherwise.",
"Do not apply tests or actions a levels less than \alevel\a."
" \b-mindepth 1\b processes all but the command line arguments.",
"File was modified \aminutes\a minutes ago.",
"Do not descend into directories in different filesystems than"
" their parents.",
"File was modified \adays\a days ago.",
"File base name (no directory components) matches \apattern\a.",
"File is written as a character format \bcpio\b(1) file entry.",
"File was modified more recently than \afile\a.",
"There is no group name matching the file group id.",
"Disable \b-physical\b leaf file \bstat\b(2) optimizations."
" Only required on filesystems with . and .. as the first entries"
" and link count not equal to 2 plus the number of subdirectories.",
"\b-not\b \aexpr\a: inverts the truth value of \aexpr\a.",
"There is no user name matching the file user id.",
"Like \b-exec\b except a prompt is written to the terminal."
" If the response does not match `[yY]].*' then the command"
" is not run and false is returned.",
"Equivalent to `\\|'. \aexpr1\a \b-or\b \aexpr2\a:"
" \aexpr2\a is not"
" evaluated if \aexpr1\a is true.",
"File path name (with directory components) matches \apattern\a.",
"File permission bits tests; \amode\a may be octal or symbolic as"
" in \bchmod\b(1). \amode\a: exactly \amode\a; \a-mode\a: all"
" \amode\a bits are set; \a+mode\a: at least one of \amode\a"
" bits are set.",
"Do not follow symbolic links. This is the default.",
"Process directories before and and after the contents are processed.",
"Print the path name (including directory components) to the"
" standard output, followed by a newline.",
"Like \b-print\b, except that the path is followed by a NUL character.",
"[+----- escape sequences -----?]"
"[+\\a?alert]"
"[+\\b?backspace]"
"[+\\f?form feed]"
"[+\\n?newline]"
"[+\\t?horizontal tab]"
"[+\\v?vertical tab]"
"[+\\xnn?hexadecimal character \ann\a]"
"[+\\nnn?octal character \annn\a]"
"[+----- format directives -----?]"
"[+%%?literal %]"
"[+%a?access time in \bctime\b(3) format]"
"[+%Ac?access time is \bstrftime\b(3) %\ac\a format]"
"[+%b?file size in 512 byte blocks]"
"[+%c?status change time in \bctime\b(3) format]"
"[+%Cc?status change time is \bstrftime\b(3) %\ac\a format]"
"[+%d?directory tree depth; 0 means command line argument]"
"[+%f?file base name (no directory components)]"
"[+%F?filesystem type name; use this for \b-fstype\b]"
"[+%g?group name, or numeric group id if no name found]"
"[+%G?numeric group id]"
"[+%h?file directory name (no base component)]"
"[+%H?command line argument under which file is found]"
"[+%i?file inode number]"
"[+%k?file size in kilobytes]"
"[+%l?symbolic link text, empty if not symbolic link]"
"[+%m?permission bits in octal]"
"[+%n?number of hard links]"
"[+%p?full path name]"
"[+%P?file path with command line argument prefix deleted]"
"[+%s?file size in bytes]"
"[+%t?modify time in \bctime\b(3) format]"
"[+%Tc?modify time is \bstrftime\b(3) %\ac\a format]"
"[+%u?user name, or numeric user id if no name found]"
"[+%U?numeric user id]"
"[+%x?%p quoted for \bxargs\b(1)]"
"[+%X?%P quoted for \bxargs\b(1)]",
"Print format \aformat\a on the standard output, interpreting"
" `\\' escapes and `%' directives. \bprintf\b(3) field width"
" and precision are interpreted as usual, but the directive"
" characters have special interpretation.",
"Print the path name (including directory components) to the"
" standard output, with \bxargs\b(1) special characters preceded"
" by \b\\\b, followed by a newline.",
"Ignored if \b-depth\b is given, otherwise do not descend the"
" current directory.",
"Path name matches the anchored regular expression \apattern\a,"
" i.e., leading ^ and traling $ are implied.",
"Reverse the \b-sort\b sense.",
"Do not warn about inaccessible directories or symbolic link loops.",
"File size is \anumber\a units (b: 512 byte blocks, c: characters"
" g: 1024*1024*1024 blocks, k: 1024 blocks, m: 1024*1024 blocks.)"
" Sizes are rounded to the next unit.",
"Search each directory in \a-option\a sort order, e.g., \b-name\b"
" sorts by name, \b-size\b sorts by size.",
"Set the current time to \aseconds\a since the epoch. Other"
" implementation defined test modes may also be enabled.",
"Always true.",
"[+b?block special]"
"[+c?character special]"
"[+d?directory]"
"[+f?regular file]"
"[+l?symbolic link]"
"[+p?named pipe (FIFO)]"
"[+s?socket]"
"[+C?contiguous]"
"[+D?door]",
"File type matches \atype\a:",
"File was accessed \adays\a days after its status changed.",
"File user id matches the name or number \aid\a.",
"Like \b-exec\b except as many file args as permitted are"
" appended to \acommand ...\a which may be executed"
" 0 or more times depending on the number of files found and"
" local system \bexec\b(2) argument limits.",
"Like \b-type\b, except if symbolic links are followed, the test"
" is applied to the symbolic link itself, otherwise the test is applied"
" to the pointed to file. Equivalent to \b-type\b if no symbolic"
" links are involved.",
0,
};
/*
* Table lookup routine
*/
static Args_t*
{
register int second;
while (*word == '-')
word++;
if (*word)
{
return argp;
}
return 0;
}
/*
* quote path component to sp for xargs(1)
*/
static void
{
register int c;
while (c = *s++)
{
}
if (term >= 0)
}
/*
* printf %! extension function
*/
static int
{
char* s;
else
s = 0;
{
case 'A':
break;
case 'b':
break;
case 'C':
break;
case 'd':
break;
case 'H':
/*FALLTHROUGH*/
case 'f':
break;
case 'F':
break;
case 'g':
break;
case 'G':
break;
case 'i':
break;
case 'k':
break;
case 'm':
break;
case 'n':
break;
case 'p':
break;
case 'P':
s += ent->fts_pathlen;
if (*s == '/')
s++;
value->s = s;
break;
case 's':
break;
case 'T':
break;
case 'u':
break;
case 'U':
break;
case 'x':
{
return -1;
}
break;
case 'X':
s += ent->fts_pathlen;
if (*s == '/')
s++;
{
return -1;
}
break;
case 'Y':
if (s)
{
switch (*s)
{
case 'H':
value->s = "ERROR";
break;
case 'h':
{
}
else
{
value->s = ".";
}
break;
case 'l':
value->s = S_ISLNK(ent->fts_statp->st_mode) && pathgetlink(PATH(ent), fp->tmp, sizeof(fp->tmp)) > 0 ? fp->tmp : "";
break;
default:
return -1;
}
break;
}
/*FALLTHROUGH*/
default:
return -1;
case 'Z':
value->i = 0;
break;
}
return 0;
}
/*
* convert the gnu-style-find printf format string for sfio extension
*/
static char*
{
register char* t;
register int c;
char* b;
stresc(s);
c = strlen(s);
{
return 0;
}
b = t;
while (c = *s++)
{
if (c == '%')
{
if (*s == '%')
{
*t++ = c;
*t++ = *s++;
}
else
{
do
{
*t++ = c;
} while ((c = *s++) && !isalpha(c));
if (!c)
break;
switch (c)
{
case 'A':
case 'C':
case 'T':
*t++ = '(';
*t++ = '%';
switch (*t++ = *s++)
{
case '@':
*(t - 1) = '#';
break;
default:
if (isalpha(*(t - 1)))
break;
*(t - 1) = 'K';
s--;
break;
}
*t++ = ')';
break;
case 'a':
case 'c':
case 't':
c = toupper(c);
break;
case 'H':
case 'h':
case 'l':
*t++ = '(';
*t++ = c;
*t++ = ')';
c = 'Y';
break;
case 'b':
case 'd':
case 'f':
case 'F':
case 'g':
case 'G':
case 'i':
case 'k':
case 'm':
case 'n':
case 'p':
case 'P':
case 's':
case 'u':
case 'U':
case 'x':
case 'X':
case 'Z':
break;
default:
return 0;
}
}
}
*t++ = c;
}
*t = 0;
return b;
}
/*
* compile the arguments
*/
static int
{
register char* b;
char* e;
char** com;
int i;
int k;
for (;;)
{
{
if (i == '?')
if (i == ':')
continue;
}
else if (i == 0)
{
{
k = e[0];
if (!e[1] || e[1] == k && !e[2])
switch (k)
{
case '(':
continue;
case ')':
continue;
case '!':
continue;
case '&':
continue;
case '|':
continue;
}
}
break;
}
{
{
return -1;
}
}
else
{
{
{
case File:
{
return -1;
}
break;
case Num:
if (*b == '+' || *b == '-')
{
b++;
}
switch (*e++)
{
default:
e--;
/*FALLTHROUGH*/
case 'b':
break;
case 'c':
break;
case 'g':
break;
case 'k':
break;
case 'm':
break;
case 'w':
break;
}
if (*e)
break;
default:
break;
}
}
}
{
case AND:
continue;
case OR:
case COMMA:
break;
case LPAREN:
return i;
{
return -1;
}
np += i;
continue;
case RPAREN:
{
return -1;
}
case LOGIC:
continue;
case META:
goto ignore;
case PHYS:
goto ignore;
case XDEV:
goto ignore;
case POST:
goto ignore;
case CHECK:
goto ignore;
case NOLEAF:
goto ignore;
case REVERSE:
goto ignore;
case SILENT:
goto ignore;
case CODES:
goto ignore;
case FAST:
goto ignore;
case ICASE:
goto ignore;
case LOCAL:
break;
case ATIME:
case CTIME:
case MTIME:
{
case '+':
break;
case '-':
break;
default:
break;
}
break;
case AMIN:
case CMIN:
case MMIN:
{
case '+':
break;
case '-':
break;
default:
break;
}
break;
case USER:
{
return -1;
}
break;
case GROUP:
{
return -1;
}
break;
case EXEC:
case OK:
case XARGS:
for (;;)
{
{
return -1;
}
if (streq(b, ";"))
break;
if (strmatch(b, "*{}*"))
{
if (!(k & CMD_INSERT) && streq(b, "{}") && (b = argv[opt_info.index]) && (streq(b, ";") || streq(b, "+") && !(i = 0)))
{
break;
}
k |= CMD_INSERT;
}
}
if (k & CMD_INSERT)
i = 1;
{
return -1;
}
break;
case MAGIC:
case MIME:
{
{
return -1;
}
}
break;
case IREGEX:
case REGEX:
{
return -1;
}
{
i |= REG_ICASE;
}
{
return -1;
}
break;
case PERM:
if (*b == '-' || *b == '+')
if (*e)
{
return -1;
}
break;
case SORT:
{
return -1;
}
goto ignore;
case TYPE:
case XTYPE:
break;
case CPIO:
goto common;
case NCPIO:
{
int fd;
/*
* set up cpio
*/
if ((fd = open(b, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0)
{
return -1;
}
ops[1] = 0;
{
return -1;
}
{
return -1;
}
}
/*FALLTHROUGH*/
case PRINT:
break;
case PRINT0:
break;
case PRINTF:
break;
case PRINTX:
break;
case FPRINT:
break;
case FPRINT0:
break;
case FPRINTF:
{
return -1;
}
break;
case FPRINTX:
break;
case LS:
break;
case FLS:
break;
case NEWER:
case ANEWER:
case CNEWER:
{
{
return -1;
}
}
break;
case CHOP:
goto ignore;
case DAYSTART:
{
time_t t;
}
goto ignore;
case MINDEPTH:
goto ignore;
case MAXDEPTH:
goto ignore;
case TEST:
goto ignore;
}
}
{
return -1;
}
if (error_info.errors)
}
/*
* This is the function that gets executed at each node
*/
static int
{
register int val = 0;
register unsigned long u;
unsigned long m;
int not = 0;
char* bp;
{
return 0;
}
{
case FTS_DP:
return 0;
break;
case FTS_NS:
return 0;
case FTS_DC:
return 0;
case FTS_DNR:
break;
case FTS_DNX:
break;
case FTS_D:
return 0;
ent->ignorecase = (state->icase || (!ent->fts_level || !ent->fts_parent->ignorecase) && strchr(astconf("PATH_ATTRIBUTES", ent->fts_name, NiL), 'c')) ? STR_ICASE : 0;
break;
default:
ent->ignorecase = ent->fts_level ? ent->fts_parent->ignorecase : (state->icase || strchr(astconf("PATH_ATTRIBUTES", ent->fts_name, NiL), 'c')) ? STR_ICASE : 0;
break;
}
return 0;
while (np)
{
{
case NOT:
continue;
case COMMA:
case LPAREN:
case OR:
return val;
{
case COMMA:
val = 1;
break;
case OR:
if (val)
return 1;
val = 1;
break;
}
break;
case LOCAL:
goto num;
case XTYPE:
val = ((state->walkflags & FTS_PHYSICAL) ? stat(PATH(ent), &st) : lstat(PATH(ent), &st)) ? 0 : st.st_mode;
goto type;
case TYPE:
type:
{
case 'b':
break;
case 'c':
break;
case 'd':
break;
case 'f':
break;
case 'l':
break;
case 'p':
break;
#ifdef S_ISSOCK
case 's':
break;
#endif
#ifdef S_ISCTG
case 'C':
break;
#endif
#ifdef S_ISDOOR
case 'D':
break;
#endif
default:
val = 0;
break;
}
break;
case PERM:
{
case '-':
break;
case '+':
break;
default:
break;
}
break;
case INUM:
goto num;
case ATIME:
goto tim;
case CTIME:
goto tim;
case MTIME:
tim:
break;
case NEWER:
break;
case ANEWER:
break;
case CNEWER:
break;
case SIZE:
goto num;
case USER:
goto num;
case NOUSER:
break;
case GROUP:
goto num;
case NOGROUP:
break;
case LINKS:
num:
u = (u + m - 1) / m;
{
case '+':
break;
case '-':
break;
default:
break;
}
break;
case EXEC:
case OK:
case XARGS:
break;
case NAME:
case INAME:
*bp = 0;
val = strgrpmatch(ent->fts_name, np->first.cp, NiL, 0, STR_MAXIMAL|STR_LEFT|STR_RIGHT|(np->action == INAME ? STR_ICASE : ent->ignorecase)) != 0;
if (bp)
*bp = '/';
break;
case LNAME:
val = S_ISLNK(ent->fts_statp->st_mode) && pathgetlink(PATH(ent), state->txt, sizeof(state->txt)) > 0 && strgrpmatch(state->txt, np->first.cp, NiL, 0, STR_MAXIMAL|STR_LEFT|STR_RIGHT|ent->ignorecase);
break;
case ILNAME:
val = S_ISLNK(ent->fts_statp->st_mode) && pathgetlink(PATH(ent), state->txt, sizeof(state->txt)) > 0 && strgrpmatch(state->txt, np->first.cp, NiL, 0, STR_MAXIMAL|STR_LEFT|STR_RIGHT|STR_ICASE);
break;
case PATH:
val = strgrpmatch(ent->fts_path, np->first.cp, NiL, 0, STR_MAXIMAL|STR_LEFT|STR_RIGHT|ent->ignorecase) != 0;
break;
case IPATH:
val = strgrpmatch(ent->fts_path, np->first.cp, NiL, 0, STR_MAXIMAL|STR_LEFT|STR_RIGHT|STR_ICASE) != 0;
break;
case MAGIC:
if (fp)
break;
case MIME:
if (fp)
break;
case REGEX:
val = 1;
else if (val == REG_NOMATCH)
val = 0;
else
{
return -1;
}
break;
case PRINT:
val = 1;
break;
case PRINTF:
val = 1;
break;
case PRINTX:
val = 1;
break;
case PRUNE:
val = 1;
break;
case FSTYPE:
break;
case LS:
fmtls(state->buf, ent->fts_path, ent->fts_statp, NiL, S_ISLNK(ent->fts_statp->st_mode) && pathgetlink(PATH(ent), state->txt, sizeof(state->txt)) > 0 ? state->txt : NiL, LS_LONG|LS_INUMBER|LS_BLOCKS);
val = 1;
break;
case EMPTY:
val = 0;
val = 1;
{
val = 0;
}
else
{
while ((dnt = readdir(dir)) && (dnt->d_name[0] == '.' && (!dnt->d_name[1] || dnt->d_name[1] == '.' && !dnt->d_name[2])));
}
break;
case CFALSE:
val = 0;
break;
case CTRUE:
val = 1;
break;
case LEVEL:
goto num;
default:
return -1;
}
break;
not = 0;
}
return val;
}
/*
* order child entries
*/
static int
{
register long n1;
register long n2;
int n;
{
case ATIME:
break;
case CTIME:
break;
case MTIME:
break;
case SIZE:
break;
default:
/*FALLTHROUGH*/
case NAME:
goto done;
}
n = -1;
n = 1;
else
n = 0;
done:
n = -n;
return n;
}
static int
{
int r;
r = 0;
{
{
r = 1;
break;
}
}
return r;
}
int
{
register char* cp;
register char** op;
int r;
if (!(state.vm = vmopen(Vmdcheap, Vmbest, 0)) || !(state.str = sfstropen()) || !(state.tmp = sfstropen()))
{
goto done;
}
sort = 0;
fp = 0;
{
}
{
goto done;
}
{
goto done;
}
goto done;
{
{
goto done;
argv[r] = 0;
{
goto done;
}
break;
}
}
if (!*op)
{
{
goto done;
}
}
else
{
{
{
}
}
fp = 0;
}
done:
{
}
return error_info.errors != 0;
}