/*      $NetBSD: option.c,v 1.29 2021/08/09 20:49:10 andvar Exp $       */

/*-
* Copyright (c) 1990, 1993, 1994
*      The Regents of the University of California.  All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Cimarron D. Taylor of the University of California, Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the
*    documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
*    may be used to endorse or promote products derived from this software
*    without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/

#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "from: @(#)option.c      8.2 (Berkeley) 4/16/94";
#else
__RCSID("$NetBSD: option.c,v 1.29 2021/08/09 20:49:10 andvar Exp $");
#endif
#endif /* not lint */

#include <sys/types.h>
#include <sys/stat.h>

#include <err.h>
#include <fts.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "find.h"

int typecompare(const void *, const void *);
static OPTION *option(char *);

/* NB: the following table must be sorted lexically. */
static OPTION const options[] = {
       { "!",          N_NOT,          c_not,          0 },
       { "(",          N_OPENPAREN,    c_openparen,    0 },
       { ")",          N_CLOSEPAREN,   c_closeparen,   0 },
       { "-a",         N_AND,          c_null,         0 },
       { "-amin",      N_AMIN,         c_amin,         1 },
       { "-and",       N_AND,          c_null,         0 },
       { "-anewer",    N_ANEWER,       c_anewer,       1 },
       { "-asince",    N_ASINCE,       c_asince,       1 },
       { "-atime",     N_ATIME,        c_atime,        1 },
       { "-cmin",      N_CMIN,         c_cmin,         1 },
       { "-cnewer",    N_CNEWER,       c_cnewer,       1 },
       { "-csince",    N_CSINCE,       c_csince,       1 },
       { "-ctime",     N_CTIME,        c_ctime,        1 },
       { "-delete",    N_DELETE,       c_delete,       0 },
       { "-depth",     N_DEPTH,        c_depth,        0 },
       { "-empty",     N_EMPTY,        c_empty,        0 },
       { "-exec",      N_EXEC,         c_exec,         1 },
       { "-execdir",   N_EXECDIR,      c_execdir,      1 },
       { "-exit",      N_EXIT,         c_exit,         0 },
       { "-false",     N_FALSE,        c_false,        0 },
       { "-flags",     N_FLAGS,        c_flags,        1 },
       { "-follow",    N_FOLLOW,       c_follow,       0 },
       { "-fprint",    N_FPRINT,       c_fprint,       1 },
       { "-fstype",    N_FSTYPE,       c_fstype,       1 },
       { "-group",     N_GROUP,        c_group,        1 },
       { "-iname",     N_INAME,        c_iname,        1 },
       { "-inum",      N_INUM,         c_inum,         1 },
       { "-iregex",    N_IREGEX,       c_iregex,       1 },
       { "-links",     N_LINKS,        c_links,        1 },
       { "-ls",        N_LS,           c_ls,           0 },
       { "-maxdepth",  N_MAXDEPTH,     c_maxdepth,     1 },
       { "-mindepth",  N_MINDEPTH,     c_mindepth,     1 },
       { "-mmin",      N_MMIN,         c_mmin,         1 },
       { "-mtime",     N_MTIME,        c_mtime,        1 },
       { "-name",      N_NAME,         c_name,         1 },
       { "-newer",     N_NEWER,        c_newer,        1 },

/* Aliases for compatibility with Gnu findutils */
       { "-neweraa",   N_ANEWER,       c_anewer,       1 },
       { "-newerat",   N_ASINCE,       c_asince,       1 },
       { "-newercc",   N_CNEWER,       c_cnewer,       1 },
       { "-newerct",   N_CSINCE,       c_csince,       1 },
       { "-newermm",   N_NEWER,        c_newer,        1 },
       { "-newermt",   N_SINCE,        c_since,        1 },

/*
* Unimplemented Gnu findutils options
*
* If you implement any of these, be sure to re-sort the table
* in ascii(7) order!
*
       { "-newerBB",   N_UNIMPL,       c_unimpl,       1 },
       { "-newerBa",   N_UNIMPL,       c_unimpl,       1 },
       { "-newerBc",   N_UNIMPL,       c_unimpl,       1 },
       { "-newerBm",   N_UNIMPL,       c_unimpl,       1 },
       { "-newerBt",   N_UNIMPL,       c_unimpl,       1 },
       { "-neweraB",   N_UNIMPL,       c_unimpl,       1 },
       { "-newerac",   N_UNIMPL,       c_unimpl,       1 },
       { "-neweram",   N_UNIMPL,       c_unimpl,       1 },
       { "-newerca",   N_UNIMPL,       c_unimpl,       1 },
       { "-newercm",   N_UNIMPL,       c_unimpl,       1 },
       { "-newercB",   N_UNIMPL,       c_unimpl,       1 },
       { "-newermB",   N_UNIMPL,       c_unimpl,       1 },
       { "-newerma",   N_UNIMPL,       c_unimpl,       1 },
       { "-newermc",   N_UNIMPL,       c_unimpl,       1 },
*
*/

       { "-nogroup",   N_NOGROUP,      c_nogroup,      0 },
/* Alias for compatibility with Gnu findutils */
       { "-not",       N_NOT,          c_not,          0 },
       { "-nouser",    N_NOUSER,       c_nouser,       0 },
       { "-o",         N_OR,           c_or,           0 },
       { "-ok",        N_OK,           c_exec,         1 },
       { "-or",        N_OR,           c_or,           0 },
       { "-path",      N_PATH,         c_path,         1 },
       { "-perm",      N_PERM,         c_perm,         1 },
       { "-print",     N_PRINT,        c_print,        0 },
       { "-print0",    N_PRINT0,       c_print0,       0 },
       { "-printx",    N_PRINTX,       c_printx,       0 },
       { "-prune",     N_PRUNE,        c_prune,        0 },
       { "-regex",     N_REGEX,        c_regex,        1 },
       { "-rm",        N_DELETE,       c_delete,       0 },
       { "-since",     N_SINCE,        c_since,        1 },
       { "-size",      N_SIZE,         c_size,         1 },
       { "-type",      N_TYPE,         c_type,         1 },
       { "-user",      N_USER,         c_user,         1 },
       { "-xdev",      N_XDEV,         c_xdev,         0 }
};

/*
* find_create --
*      create a node corresponding to a command line argument.
*
* TODO:
*      add create/process function pointers to node, so we can skip
*      this switch stuff.
*/
PLAN *
find_create(char ***argvp)
{
       OPTION *p;
       PLAN *new;
       char **argv;
       char *opt;

       argv = *argvp;
       opt = *argv;

       if ((p = option(opt)) == NULL)
               errx(1, "%s: unknown option", opt);
       ++argv;
       if (p->arg && !*argv)
               errx(1, "%s: requires additional arguments", opt);

       new = (p->create)(&argv, p->token == N_OK, opt);

       *argvp = argv;
       return (new);
}

static OPTION *
option(char *name)
{
       OPTION tmp;

       tmp.name = name;
       return ((OPTION *)bsearch(&tmp, options,
           sizeof(options)/sizeof(OPTION), sizeof(OPTION), typecompare));
}

int
typecompare(const void *a, const void *b)
{

       return (strcmp(((const OPTION *)a)->name, ((const OPTION *)b)->name));
}