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

📄 tac.c

📁 HLPDK V10.0+ System Extension Library
💻 C
📖 第 1 页 / 共 2 页
字号:
  int bytes_read;

#ifdef MSDOS
  char *p;

  if ((p = getenv ("TMP")) || (p = getenv ("TEMP")))
    {
      int len = strlen (p);
      workplate = (char *) xmalloc (sizeof (template) + len + 1);
      strcpy (workplate, p);
      p = workplate + len - 1;
      if (*p == '/' || *p == '\\')	/*  strip trailing slash */
	*p = '\0';
    }
  else
    {
      workplate = (char *) xmalloc (sizeof (template) + 2);
      strcpy (workplate, ".");
    }
  strcat (workplate, template);
#else /* not MSDOS */
  strcpy (workplate, template);
#endif /* not MSDOS */
  tempfile = mktemp (workplate);

#ifdef MSDOS
  fd = open (tempfile, O_CREAT|O_TRUNC|O_RDWR|O_BINARY, S_IWRITE|S_IREAD);
#else /* not MSDOS */
  fd = creat (tempfile, 0600);
#endif /* not MSDOS */
  if (fd == -1)
    {
      error (0, errno, "%s", tempfile);
      cleanup ();
    }

  while ((bytes_read = read (0, buffer, read_size)) > 0)
    if (write (fd, buffer, bytes_read) != bytes_read)
      {
	error (0, errno, "%s", tempfile);
	cleanup ();
      }
  close (fd);
  if (bytes_read == -1)
    {
      error (0, errno, "read error");
      cleanup ();
    }
}

/* Print FILE in reverse.
   Return 0 if ok, 1 if an error occurs. */

int
tac_file (file)
     char *file;
{
  int fd, errors;

#ifdef MSDOS
  fd = open (file, O_RDONLY|O_BINARY);
#else /* not MSDOS */
  fd = open (file, 0);
#endif /* not MSDOS */
  if (fd == -1)
    {
      error (0, errno, "%s", file);
      return 1;
    }
  errors = tac (fd, file);
  close (fd);
  return errors;
}

/* Print in reverse the file open on descriptor FD for reading FILE.
   Return 0 if ok, 1 if an error occurs. */

int
tac (fd, file)
     int fd;
     char *file;
{
  /* Pointer to the location in `buffer' where the search for
     the next separator will begin. */
  char *match_start;
  /* Pointer to one past the rightmost character in `buffer' that
     has not been printed yet. */
  char *past_end;
  unsigned saved_record_size;	/* Length of the record growing in `buffer'. */
  off_t file_pos;		/* Offset in the file of the next read. */
  /* Nonzero if `output' has not been called yet for any file.
     Only used when the separator is attached to the preceding record. */
  int first_time = 1;
  char first_char = *separator;	/* Speed optimization, non-regexp. */
  char *separator1 = separator + 1; /* Speed optimization, non-regexp. */
  int match_length1 = match_length - 1; /* Speed optimization, non-regexp. */
  struct re_registers regs;
  int errors = 0;

  /* Find the size of the input file. */
  file_pos = lseek (fd, (off_t) 0, L_XTND);
  if (file_pos < 1)
    return 0;			/* It's an empty file. */

  /* Arrange for the first read to lop off enough to leave the rest of the
     file a multiple of `read_size'.  Since `read_size' can change, this may
     not always hold during the program run, but since it usually will, leave
     it here for i/o efficiency (page/sector boundaries and all that).
     Note: the efficiency gain has not been verified. */
#ifdef MSDOS
  saved_record_size = (unsigned int) (file_pos % read_size);
#else /* not MSDOS */
  saved_record_size = file_pos % read_size;
#endif /* not MSDOS */
  if (saved_record_size == 0)
    saved_record_size = read_size;
  file_pos -= saved_record_size;
  /* `file_pos' now points to the start of the last (probably partial) block
     in the input file. */

  lseek (fd, file_pos, L_SET);
  if (read (fd, buffer, saved_record_size) != saved_record_size)
    {
      error (0, 1, "%s", file);
      return 1;
    }

#ifdef MSDOS
  /* Some loosing editors add one or more ^Z to the end of a text file and
     loosing MS-DOS devices interpret this as End Of File.  We turn them
     into spaces and print a warning message.  */
    {
      char *ctrl_z = buffer + saved_record_size - 1;
      if (*ctrl_z == '\032')
	{
	  *ctrl_z = ' ';
	  error (0, 0, "%s: trailing ^Z translated to space.", file);
	  while (*--ctrl_z == '\032')
	    *ctrl_z = ' ';
	}
    }
#endif /* MSDOS */

  match_start = past_end = buffer + saved_record_size;
  /* For non-regexp search, move past impossible positions for a match. */
  if (sentinel_length)
    match_start -= match_length1;

  for (;;)
    {
      /* Search backward from `match_start' - 1 to `buffer' for a match
	 with `separator'; for speed, use strncmp if `separator' contains no
	 metacharacters.
	 If the match succeeds, set `match_start' to point to the start of
	 the match and `match_length' to the length of the match.
	 Otherwise, make `match_start' < `buffer'. */
      if (sentinel_length == 0)
	{
	  int i = match_start - buffer;
	  int ret;

	  ret = re_search (&compiled_separator, buffer, i, i - 1, -i, &regs);
	  if (ret == -1)
	    match_start = buffer - 1;
	  else if (ret == -2)
	    {
	      error (0, 0, "error in regular expression search");
	      cleanup ();
	    }
	  else
	    {
	      match_start = buffer + regs.start[0];
	      match_length = regs.end[0] - regs.start[0];
	    }
	}
      else
	{
	  /* `match_length' is constant for non-regexp boundaries. */
	  while (*--match_start != first_char
		 || (match_length1 && strncmp (match_start + 1, separator1,
					       match_length1)))
	    /* Do nothing. */ ;
	}

      /* Check whether we backed off the front of `buffer' without finding
         a match for `separator'. */
      if (match_start < buffer)
	{
	  if (file_pos == 0)
	    {
	      /* Hit the beginning of the file; print the remaining record. */
	      output (buffer, past_end);
	      return errors;
	    }

	  saved_record_size = past_end - buffer;
	  if (saved_record_size > read_size)
	    {
	      /* `buffer_size' is about twice `read_size', so since
		 we want to read in another `read_size' bytes before
		 the data already in `buffer', we need to increase
		 `buffer_size'. */
	      char *newbuffer;
	      int offset = sentinel_length ? sentinel_length : 1;

	      read_size *= 2;
	      buffer_size = read_size * 2 + sentinel_length + 2;
	      newbuffer = xrealloc (buffer - offset, buffer_size) + offset;
	      /* Adjust the pointers for the new buffer location.  */
	      match_start += newbuffer - buffer;
	      past_end += newbuffer - buffer;
	      buffer = newbuffer;
	    }

	  /* Back up to the start of the next bufferfull of the file.  */
	  if (file_pos >= read_size)
	    file_pos -= read_size;
	  else
	    {
	      read_size = (unsigned) file_pos;
	      file_pos = 0;
	    }
	  lseek (fd, file_pos, L_SET);

	  /* Shift the pending record data right to make room for the new. */
	  bcopy (buffer, buffer + read_size, saved_record_size);
	  past_end = buffer + read_size + saved_record_size;
	  /* For non-regexp searches, avoid unneccessary scanning. */
	  if (sentinel_length)
	    match_start = buffer + read_size;
	  else
	    match_start = past_end;

	  if (read (fd, buffer, read_size) != read_size)
	    {
	      error (0, errno, "%s", file);
	      return 1;
	    }
	}
      else
	{
	  /* Found a match of `separator'. */
	  if (separator_ends_record)
	    {
	      char *match_end = match_start + match_length;

	      /* If this match of `separator' isn't at the end of the
	         file, print the record. */
	      if (first_time == 0 || match_end != past_end)
		output (match_end, past_end);
	      past_end = match_end;
	      first_time = 0;
	    }
	  else
	    {
	      output (match_start, past_end);
	      past_end = match_start;
	    }
	  match_start -= match_length - 1;
	}
    }
}

/* Print the characters from START to PAST_END - 1.
   If START is NULL, just flush the buffer. */

void
output (start, past_end)
     char *start;
     char *past_end;
{
  static char buffer[WRITESIZE];
  static int bytes_in_buffer = 0;
  int bytes_to_add = past_end - start;
  int bytes_available = WRITESIZE - bytes_in_buffer;

  if (start == 0)
    {
      xwrite (1, buffer, bytes_in_buffer);
      bytes_in_buffer = 0;
      return;
    }
  
  /* Write out as many full buffers as possible. */
  while (bytes_to_add >= bytes_available)
    {
      bcopy (start, buffer + bytes_in_buffer, bytes_available);
      bytes_to_add -= bytes_available;
      start += bytes_available;
      xwrite (1, buffer, WRITESIZE);
      bytes_in_buffer = 0;
      bytes_available = WRITESIZE;
    }

  bcopy (start, buffer + bytes_in_buffer, bytes_to_add);
  bytes_in_buffer += bytes_to_add;
}

SIGTYPE
cleanup ()
{
  unlink (tempfile);
  exit (1);
}

void
xwrite (desc, buffer, size)
     int desc;
     char *buffer;
     int size;
{
  if (write (desc, buffer, size) != size)
    {
      error (0, errno, "write error");
      cleanup ();
    }
}


/* Allocate N bytes of memory dynamically, with error checking.  */

char *
xmalloc (n)
     unsigned n;
{
  char *p;

  p = malloc (n);
  if (p == 0)
    {
      error (0, 0, "virtual memory exhausted");
      cleanup ();
    }
  return p;
}

/* Change the size of memory area P to N bytes, with error checking. */

char *
xrealloc (p, n)
     char *p;
     unsigned n;
{
  p = realloc (p, n);
  if (p == 0)
    {
      error (0, 0, "virtual memory exhausted");
      cleanup ();
    }
  return p;
}

⌨️ 快捷键说明

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