⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 test.c

📁 《linux应用开发技术详解》的配套代码
💻 C
📖 第 1 页 / 共 2 页
字号:

	  if (argv[op][2] == 'f' && !argv[op][3])
	    {
	      /* ef - hard link? */
	      pos += 3;
	      if (l_is_l || r_is_l)
		test_syntax_error (_("-ef does not accept -l\n"), NULL);
	      if (stat (argv[op - 1], &stat_buf) < 0)
		return (FALSE);
	      if (stat (argv[op + 1], &stat_spare) < 0)
		return (FALSE);
	      return (TRUE ==
		      (stat_buf.st_dev == stat_spare.st_dev &&
		       stat_buf.st_ino == stat_spare.st_ino));
	    }
	  break;

	case 'o':
	  if ('t' == argv[op][2] && '\000' == argv[op][3])
	    {
	      /* ot - older than */
	      time_t lt, rt;
	      int le, re;
	      pos += 3;
	      if (l_is_l || r_is_l)
		test_syntax_error (_("-ot does not accept -l\n"), NULL);
	      le = age_of (argv[op - 1], &lt);
	      re = age_of (argv[op + 1], &rt);
	      return le < re || (re == 0 && lt < rt);
	    }
	  break;
	}
      test_syntax_error (_("unknown binary operator"), argv[op]);
    }

  if (argv[op][0] == '=' && !argv[op][1])
    {
      value = (strcmp (argv[pos], argv[pos + 2]) == 0);
      pos += 3;
      return (TRUE == value);
    }

  if (strcmp (argv[op], "!=") == 0)
    {
      value = (strcmp (argv[pos], argv[pos + 2]) != 0);
      pos += 3;
      return (TRUE == value);
    }

  /* Not reached.  */
  abort ();
}

static int
unary_operator (void)
{
  int value;
  struct stat stat_buf;

  switch (argv[pos][1])
    {
    default:
      return (FALSE);

      /* All of the following unary operators use unary_advance (), which
	 checks to make sure that there is an argument, and then advances
	 pos right past it.  This means that pos - 1 is the location of the
	 argument. */

    case 'a':			/* file exists in the file system? */
    case 'e':
      unary_advance ();
      value = -1 != test_stat (argv[pos - 1], &stat_buf);
      return (TRUE == value);

    case 'r':			/* file is readable? */
      unary_advance ();
      value = -1 != eaccess (argv[pos - 1], R_OK);
      return (TRUE == value);

    case 'w':			/* File is writable? */
      unary_advance ();
      value = -1 != eaccess (argv[pos - 1], W_OK);
      return (TRUE == value);

    case 'x':			/* File is executable? */
      unary_advance ();
      value = -1 != eaccess (argv[pos - 1], X_OK);
      return (TRUE == value);

    case 'O':			/* File is owned by you? */
      unary_advance ();
      if (test_stat (argv[pos - 1], &stat_buf) < 0)
	return (FALSE);

      return (TRUE == (geteuid () == stat_buf.st_uid));

    case 'G':			/* File is owned by your group? */
      unary_advance ();
      if (test_stat (argv[pos - 1], &stat_buf) < 0)
	return (FALSE);

      return (TRUE == (getegid () == stat_buf.st_gid));

    case 'f':			/* File is a file? */
      unary_advance ();
      if (test_stat (argv[pos - 1], &stat_buf) < 0)
	return (FALSE);

      /* Under POSIX, -f is true if the given file exists
	 and is a regular file. */
      return (TRUE == ((S_ISREG (stat_buf.st_mode)) ||
		       (0 == (stat_buf.st_mode & S_IFMT))));

    case 'd':			/* File is a directory? */
      unary_advance ();
      if (test_stat (argv[pos - 1], &stat_buf) < 0)
	return (FALSE);

      return (TRUE == (S_ISDIR (stat_buf.st_mode)));

    case 's':			/* File has something in it? */
      unary_advance ();
      if (test_stat (argv[pos - 1], &stat_buf) < 0)
	return (FALSE);

      return (TRUE == (stat_buf.st_size > (off_t) 0));

    case 'S':			/* File is a socket? */
#if !defined (S_ISSOCK)
      return (FALSE);
#else
      unary_advance ();

      if (test_stat (argv[pos - 1], &stat_buf) < 0)
	return (FALSE);

      return (TRUE == (S_ISSOCK (stat_buf.st_mode)));
#endif				/* S_ISSOCK */

    case 'c':			/* File is character special? */
      unary_advance ();
      if (test_stat (argv[pos - 1], &stat_buf) < 0)
	return (FALSE);

      return (TRUE == (S_ISCHR (stat_buf.st_mode)));

    case 'b':			/* File is block special? */
      unary_advance ();
      if (test_stat (argv[pos - 1], &stat_buf) < 0)
	return (FALSE);

      return (TRUE == (S_ISBLK (stat_buf.st_mode)));

    case 'p':			/* File is a named pipe? */
      unary_advance ();
#ifndef S_ISFIFO
      return (FALSE);
#else
      if (test_stat (argv[pos - 1], &stat_buf) < 0)
	return (FALSE);
      return (TRUE == (S_ISFIFO (stat_buf.st_mode)));
#endif				/* S_ISFIFO */

    case 'L':			/* Same as -h  */
      /*FALLTHROUGH*/

    case 'h':			/* File is a symbolic link? */
      unary_advance ();
#ifndef S_ISLNK
      return (FALSE);
#else
      /* An empty filename is not a valid pathname. */
      if ((argv[pos - 1][0] == '\0') ||
	  (lstat (argv[pos - 1], &stat_buf) < 0))
	return (FALSE);

      return (TRUE == (S_ISLNK (stat_buf.st_mode)));
#endif				/* S_IFLNK */

    case 'u':			/* File is setuid? */
      unary_advance ();
#ifndef S_ISUID
      return (FALSE);
#else
      if (test_stat (argv[pos - 1], &stat_buf) < 0)
	return (FALSE);

      return (TRUE == (0 != (stat_buf.st_mode & S_ISUID)));
#endif

    case 'g':			/* File is setgid? */
      unary_advance ();
#ifndef S_ISGID
      return (FALSE);
#else
      if (test_stat (argv[pos - 1], &stat_buf) < 0)
	return (FALSE);

      return (TRUE == (0 != (stat_buf.st_mode & S_ISGID)));
#endif

    case 'k':			/* File has sticky bit set? */
      unary_advance ();
      if (test_stat (argv[pos - 1], &stat_buf) < 0)
	return (FALSE);
#ifndef S_ISVTX
      /* This is not Posix, and is not defined on some Posix systems. */
      return (FALSE);
#else
      return (TRUE == (0 != (stat_buf.st_mode & S_ISVTX)));
#endif

    case 't':			/* File (fd) is a terminal? */
      {
	intmax_t fd;
	advance (0);
	if (pos < argc)
	  {
	    if (!isint (argv[pos], &fd))
	      integer_expected_error (_("after -t"));
	    advance (0);
	  }
	else
	  {
	    fd = 1;
	  }
	return (TRUE == (fd == (int) fd && isatty (fd)));
      }

    case 'n':			/* True if arg has some length. */
      unary_advance ();
      return (TRUE == (argv[pos - 1][0] != 0));

    case 'z':			/* True if arg has no length. */
      unary_advance ();
      return (TRUE == (argv[pos - 1][0] == '\0'));
    }
}

/*
 * and:
 *	term
 *	term '-a' and
 */
static int
and (void)
{
  int value;

  value = term ();
  while ((pos < argc) && strcmp (argv[pos], "-a") == 0)
    {
      advance (0);
      value = TRUTH_AND (value, and ());
    }
  return (TRUE == value);
}

/*
 * or:
 *	and
 *	and '-o' or
 */
static int
or (void)
{
  int value;

  value = and ();

  while ((pos < argc) && strcmp (argv[pos], "-o") == 0)
    {
      advance (0);
      value = TRUTH_OR (value, or ());
    }

  return (TRUE == value);
}

/*
 * expr:
 *	or
 */
static int
expr (void)
{
  if (pos >= argc)
    beyond ();

  return (FALSE ^ (or ()));		/* Same with this. */
}

/* Return TRUE if S is one of the test command's binary operators. */
static int
binop (char *s)
{
  return ((STREQ (s,   "=")) || (STREQ (s,  "!=")) || (STREQ (s, "-nt")) ||
	  (STREQ (s, "-ot")) || (STREQ (s, "-ef")) || (STREQ (s, "-eq")) ||
	  (STREQ (s, "-ne")) || (STREQ (s, "-lt")) || (STREQ (s, "-le")) ||
	  (STREQ (s, "-gt")) || (STREQ (s, "-ge")));
}

/* Return nonzero if OP is one of the test command's unary operators. */
static int
unop (int op)
{
  return (member (op, "abcdefgkLhprsStuwxOGnz"));
}

static int
one_argument (const char *s)
{
  if (STREQ (s, "-t"))
    return (TRUE == (isatty (1)));

  return strlen (s) != 0;
}

static int
two_arguments (void)
{
  int value;

  if (STREQ (argv[pos], "!"))
    value = ! one_argument (argv[pos+1]);
  else if (argv[pos][0] == '-'
	   && argv[pos][1] != '\0'
	   && argv[pos][2] == '\0')
    {
      if (unop (argv[pos][1]))
	value = unary_operator ();
      else
	test_syntax_error (_("%s: unary operator expected\n"), argv[pos]);
    }
  else
    beyond ();
  return (value);
}

static int
three_arguments (void)
{
  int value;

  if (STREQ (argv[pos], "!"))
    {
      advance (1);
      value = !two_arguments ();
    }
  else if (binop (argv[pos+1]))
    {
      value = binary_operator ();
      pos = argc;
    }
  else if ((STREQ (argv[pos+1], "-a")) || (STREQ (argv[pos+1], "-o")) ||
	   (argv[pos][0] == '('))
    value = expr ();
  else
    test_syntax_error (_("%s: binary operator expected\n"), argv[pos+1]);
  return (value);
}

/* This is an implementation of a Posix.2 proposal by David Korn. */
static int
posixtest (void)
{
  int value;

  switch (argc - 1)	/* one extra passed in */
    {
      case 0:
	value = FALSE;
	pos = argc;
	break;

      case 1:
	value = one_argument (argv[1]);
	pos = argc;
	break;

      case 2:
	value = two_arguments ();
	pos = argc;
	break;

      case 3:
	value = three_arguments ();
	break;

      case 4:
	if (STREQ (argv[pos], "!"))
	  {
	    advance (1);
	    value = !three_arguments ();
	    break;
	  }
	/* FALLTHROUGH */
      case 5:
      default:
	value = expr ();
    }

  return (value);
}

#if defined (TEST_STANDALONE)
# include "long-options.h"
# include "closeout.h"

void
usage (int status)
{
  if (status != 0)
    fprintf (stderr, _("Try `%s --help' for more information.\n"),
	     program_name);
  else
    {
      printf (_("\
Usage: %s EXPRESSION\n\
  or:  [ EXPRESSION ]\n\
  or:  %s OPTION\n\
"),
	      program_name, program_name);
      fputs (_("\
Exit with the status determined by EXPRESSION.\n\
\n\
"), stdout);
      fputs (HELP_OPTION_DESCRIPTION, stdout);
      fputs (VERSION_OPTION_DESCRIPTION, stdout);
      fputs (_("\
\n\
EXPRESSION is true or false and sets exit status.  It is one of:\n\
"), stdout);
      fputs (_("\
\n\
  ( EXPRESSION )               EXPRESSION is true\n\
  ! EXPRESSION                 EXPRESSION is false\n\
  EXPRESSION1 -a EXPRESSION2   both EXPRESSION1 and EXPRESSION2 are true\n\
  EXPRESSION1 -o EXPRESSION2   either EXPRESSION1 or EXPRESSION2 is true\n\
"), stdout);
      fputs (_("\
\n\
  [-n] STRING          the length of STRING is nonzero\n\
  -z STRING            the length of STRING is zero\n\
  STRING1 = STRING2    the strings are equal\n\
  STRING1 != STRING2   the strings are not equal\n\
"), stdout);
      fputs (_("\
\n\
  INTEGER1 -eq INTEGER2   INTEGER1 is equal to INTEGER2\n\
  INTEGER1 -ge INTEGER2   INTEGER1 is greater than or equal to INTEGER2\n\
  INTEGER1 -gt INTEGER2   INTEGER1 is greater than INTEGER2\n\
  INTEGER1 -le INTEGER2   INTEGER1 is less than or equal to INTEGER2\n\
  INTEGER1 -lt INTEGER2   INTEGER1 is less than INTEGER2\n\
  INTEGER1 -ne INTEGER2   INTEGER1 is not equal to INTEGER2\n\
"), stdout);
      fputs (_("\
\n\
  FILE1 -ef FILE2   FILE1 and FILE2 have the same device and inode numbers\n\
  FILE1 -nt FILE2   FILE1 is newer (modification date) than FILE2\n\
  FILE1 -ot FILE2   FILE1 is older than FILE2\n\
"), stdout);
      fputs (_("\
\n\
  -b FILE     FILE exists and is block special\n\
  -c FILE     FILE exists and is character special\n\
  -d FILE     FILE exists and is a directory\n\
  -e FILE     FILE exists\n\
"), stdout);
      fputs (_("\
  -f FILE     FILE exists and is a regular file\n\
  -g FILE     FILE exists and is set-group-ID\n\
  -h FILE     FILE exists and is a symbolic link (same as -L)\n\
  -G FILE     FILE exists and is owned by the effective group ID\n\
  -k FILE     FILE exists and has its sticky bit set\n\
"), stdout);
      fputs (_("\
  -L FILE     FILE exists and is a symbolic link (same as -h)\n\
  -O FILE     FILE exists and is owned by the effective user ID\n\
  -p FILE     FILE exists and is a named pipe\n\
  -r FILE     FILE exists and is readable\n\
  -s FILE     FILE exists and has a size greater than zero\n\
"), stdout);
      fputs (_("\
  -S FILE     FILE exists and is a socket\n\
  -t [FD]     file descriptor FD (stdout by default) is opened on a terminal\n\
  -u FILE     FILE exists and its set-user-ID bit is set\n\
  -w FILE     FILE exists and is writable\n\
  -x FILE     FILE exists and is executable\n\
"), stdout);
      fputs (_("\
\n\
Beware that parentheses need to be escaped (e.g., by backslashes) for shells.\n\
INTEGER may also be -l STRING, which evaluates to the length of STRING.\n\
"), stdout);
      printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
    }
  exit (status);
}
#endif /* TEST_STANDALONE */

#if !defined (TEST_STANDALONE)
# define main test_command
#endif

#define AUTHORS N_ ("FIXME: ksb and mjb")

/*
 * [:
 *	'[' expr ']'
 * test:
 *	test expr
 */
int
main (int margc, char **margv)
{
  int value;

#if !defined (TEST_STANDALONE)
  int code;

  code = setjmp (test_exit_buf);

  if (code)
    return (test_error_return);
#else /* TEST_STANDALONE */
  program_name = margv[0];
  setlocale (LC_ALL, "");
  bindtextdomain (PACKAGE, LOCALEDIR);
  textdomain (PACKAGE);

  atexit (close_stdout);
#endif /* TEST_STANDALONE */

  argv = margv;

  if (margv[0] && strcmp (margv[0], "[") == 0)
    {
      /* Don't recognize --help or --version if POSIXLY_CORRECT is set.  */
      if (getenv ("POSIXLY_CORRECT") == NULL)
	parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
			    AUTHORS, usage);

      --margc;

      if (margc < 2)
	test_exit (SHELL_BOOLEAN (FALSE));

      if (margv[margc] && strcmp (margv[margc], "]") != 0)
	test_syntax_error (_("missing `]'\n"), NULL);
    }

  argc = margc;
  pos = 1;

  if (pos >= argc)
    test_exit (SHELL_BOOLEAN (FALSE));

  parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
		      AUTHORS, usage);
  value = posixtest ();

  if (pos != argc)
    test_syntax_error (_("too many arguments\n"), NULL);

  test_exit (SHELL_BOOLEAN (value));
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -