/* cat.c -- catenate and print files

   Calling syntax:
     cat [ -u ] [ -s ] [ -n ] [ -v ] file1 ...

     if the filename - is encountered, the standard input will be used.

   Effect: 

	Cat reads each file and writes it to the standard output.

	Io is written in 1024-byte blocks, unless the -u option is in effect.

     The -n option causes the lines to be numbered from 1.  Specifying -b 
     with -n causes numbers to be omitted from blank lines.

	The -s option causee the output to be single spaced. (Blank lines are
	not printed)

	The -v option causes non-printing charactesr to be printed visibly.
     (Meta characters are printed M-<char>.  Control characters, ^<char>,
      rubout is printed as ^?)

	The -e option causes the ends of lines to be followed by the 
	character '$'.  The -t option causes tabs to be printed as ^I.

*/ 

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

#define BUFSIZE 1024

main(argc, argv)
   int argc;
   char *argv[];
   {

   FILE *f; 		    /* Input file */
   struct stat st;      /* File status structure for input file */
   char buf[BUFSIZE];   /* Io buffer */
   register c;
   char lc;
   int dev, ino;
   int uflag = 0;
   int sflag = 0;
   int vflag = 0;
   int nflag = 0;
   int tflag = 0;
   int bflag = 0;
   int eflag = 0;
   int lineno = 1;

   while ((--argc > 0) && (**(++argv) == '-'))
	 while (*(++(*argv)) != 0)
	   switch (**argv)
	      {
		 case 'u':
		    uflag++;
		    break;
		 case 's':
		    sflag++;
		    break;
		 case 'v':
		    vflag++;
		    break;
		 case 't':
		    tflag++;
		    vflag++;
		    break;
		 case 'b':
		    bflag++;
		    nflag++;
		    break;
		 case 'e':
		    eflag++;
		    vflag++;
		    break;
		 case 'n':
		    nflag++;
		    break;
		 default:
			fprintf(stderr, "cat: unknown flag %c.\n", **argv);
			return;
		 }



   if (uflag)
	 setbuf(stdout, NULL);
   else
	 setbuf(stdout, buf);


   /* Record the device and inode */
   fstat(fileno(stdout), &st);
   dev = st.st_dev;
   ino = st.st_ino;

   /* Special case: if there are no other arguments */
   if (argc == 0)
	 {
      while ((c = getchar()) != EOF)
	    putchar(c);
	 return;
	 }

   for (;;)
      {
      /* Open the input file */   
      if (((**argv == '-') && ((*argv)[1] == 0)))
         f=stdin;
      else
	    {
	    /* First check if the file is the same as the standard output */
	    if (stat(*argv, &st) < 0)
		  {
		  if (!sflag)
		     fprintf(stderr, "cat: file %s doesn't exist.\n", *argv);
		  return;
		  }
	       
	    if ((st.st_dev  == dev) && (st.st_ino == ino))
		  {
		  if (!sflag)
	          fprintf(stderr, 
				   "cat: input file %s same as standard output.\n",
			       *argv);
	       return;
		  }
         if ((f = fopen(*argv, "r")) == NULL)
            {
            if (!sflag)
		     fprintf(stderr, "cat: error opening input file %s\n", *argv);
		  fclose(f);
	 	  return;
            }
	    }
      argc--;
      argv++;

	 /* Copy the contents to the standard output */
	 if (!vflag && !nflag && !sflag)
         while ((c = getc(f)) != EOF)
	       putchar(c);
	 else
	    {
	    lineno=0;
	    lc = '\n';
	    while ((c = getc(f)) != EOF)
		  {
		  if (lc == '\n')
			{
		     if (sflag && (c == '\n'))
			   continue;
			if (nflag && (!bflag || (c != '\n')))
			   printf("%6d", lineno++);
			}

		  lc = c;

		  if (vflag)
			{
			if (c & 0200)
			   printf("M-");

			if (c == '\n')
			   {
			   if (eflag)
				 putchar('$');
			   putchar('\n');
			   }
			else if ((c == '\t') && !tflag)
			   putchar('\t');
			else
			   {
			   c &= 0177;
			   if (c < ' ')
			      printf("^%c", c+'@');
			   else if (c == 0177)
				 printf("^?");
			   else
			      putchar(c);
			   }
		     }

		 else
		    putchar(c);


		 }
	   }			

     fclose(f);

     if (ferror(stdout))
	   {	
	   if (!sflag)
	      fprintf(stderr, "cat: error writing to standard output.\n");
	   return;
	   }	

     if (argc == 0)
        return;
	}
  }
