/* cp.c -- copy file 

  Calling syntax: cp [ -i ] file1 file2
                  or cp [  -i ] file ... directory

  Effect:
	The contents of file1 are copied to file2.  
     In the second form, one or more files are copied into the directory 
     with their original file names.

	Cp will not copy a file into itself.

	If -i option is specified, cp will prompt the user whenever
     an already existing file is about to be overwritten.  Only if the
     user types 'y', it will overwrite the file. 

  Implementation
	Parse the options, if any.
	Check if there are the right number of arguments.
	Record whether the last file is a directory.
	For X being each element of argv, except the last one:
	   Copy the last element of argv to buf.
	   If buf is the name of a directory, then append X to buf.
	   infile = Open(X, read)
	   outfile = creat(buf, mode of X)
	   Copy the data from infile to outfile.

*/
	   




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

#define BUFSIZE 512

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


   struct stat st;                 /* File status structure */
   unsigned short dev, ino, mode;  /* temp variables for st elements */
   char buf[BUFSIZE];			/* IO buffer */
   char *temp1, *temp2, *temp3;
   int retval;
   int dirflag = 0;			/* True if the last file is a directory */
   int inf, outf;			/* The input and output file descriptors */
   int iflag = 0;

   /* Parse the flags, if any */
   while ((--argc > 0) && (**(++argv) == '-'))
	 while (*(++(*argv)) != 0)
	   switch (**argv)
	      {
           case 'i':
		    iflag++;
		    break;
	 	 default:
			fprintf(stderr, "cp: unknown flag %c.\n", **argv);
			return;
		 }

   if (argc < 2)
	 {
	 fprintf(stderr, "Usage: cp f1 f2; or cp f1 f2 ... dir\n");
	 return;
	 }


   stat(argv[argc-1], &st);
   if (st.st_mode & S_IFDIR)
	 dirflag++;
   else
	 if (argc > 2)
	    {
	    fprintf(stderr, "Usage: cp f1 f2; or cp f1 f2 ... dir\n");
	    return;
	    }

   while (argc > 1)
	 {
	 temp1 = buf;
	 temp2 = argv[argc-1];
	 while ((*temp1++ = *temp2++) != 0);

	 if (dirflag)
	    {
	    temp2 = *argv;
	    temp3 = temp2;
	    *(temp1-1) = '/';
	    while (*temp2 != 0)
		  if (*temp2++ == '/')
		     temp3 = temp2;
	    while ((*temp1++ = *temp3++) != 0);
	    }


	
      /* Check if the file exists */
	 retval = stat(*argv, &st);
	 if (retval < 0)
	    {
	    fprintf(stderr, "cp: file %s doesn't exist.\n", *argv);
	    return;
	    }

	 dev = st.st_dev;
	 ino = st.st_ino;
	 mode = st.st_mode;

	 /* Check if the file is a directory */
	 if (mode & S_IFDIR)
	    {
	    fprintf(stderr, "Usage: cp f1 f2; or cp f1 f2 ... dir\n");
	    return;
	    }

	 /* Abort if the file will be copied to itself.  Also, ask user
         if the file already exists, and iflag is true. */
	 if (stat(buf, &st) >= 0)
	    {
	    if ((st.st_dev == dev) && (st.st_ino == ino))
		  {
		  fprintf(stderr, "cp: can't copy %s to itself.\n", *argv);
		  argv++;
		  argc--;
		  continue;
		  }
	    if (iflag)
		  {
	       retval = fstat(stdin, &st);
	       if (retval && (st.st_mode & S_IFCHR))
		     {
			printf("cp: file %s already exists.  Overwrite? (y or n) ");
			putchar(-1);
		     if (getchar() != 'y')
			   {
			   printf(" No.\n");
			   argv++;
			   argc--;
			   continue;
			   }
		     else
			   printf(" Yes.\n");
			}
		  }
	    }

	 /* Open the input file */
	 if ((inf = open(*argv, 0)) == -1)
	    {
	    fprintf(stderr, "cp: error opening input file %s.\n", *argv);
         return;
	    }

	 /* Create the output file */
	 if ((outf = creat(buf, mode)) == -1)
	    {
	    fprintf(stderr, "cp: error creating output file %s.\n", buf);
	    close(inf);
	    return;
	    }

	 /* Copy the data */
	 while ((retval = read(inf, buf, BUFSIZE)) != 0)
	    {
	    if (retval == -1)
		  {
		  fprintf(stderr, "cp: error reading from file %s.\n", *argv);
		  close(inf);
		  close(outf);
		  return;
		  }
	    if (write(outf, buf, retval) != retval)
		  {
		  fprintf(stderr, "cp: error writing to file.\n");
		  close(inf);
		  close(outf);
		  return;
		  }
	    }

	 argc--;
	 argv++;
	 }
   }
