/**
*** XPG - Graphical User Interface for Postgres
*** Copyright (C) 1993  Ranen Goren (ranen@cs.huji.ac.il).

*** This program is free software; you can redistribute it and/or modify
*** it under the terms of the GNU General Public License as published by
*** the Free Software Foundation; either version 2 of the License, or
*** (at your option) any later version.

*** This program is distributed in the hope that it will be useful,
*** but WITHOUT ANY WARRANTY; without even the implied warranty of
*** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*** GNU General Public License for more details.

*** You should have received a copy of the GNU General Public License
*** along with this program; if not, write to the Free Software
*** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
**/


/*
 *  icopy -- Inversion file system copy program
 *
 *	Icopy moves files between the Unix file system and Inversion.
 */
#include "large_obj.h"

#include <sys/file.h>
#include <stdio.h>

#include "tmp/c.h"
#include "tmp/libpq-fe.h"
#include "tmp/libpq-fs.h"
#include "catalog/pg_lobj.h"

char *ProgName;
extern char *PQhost;
extern char *PQport;
extern char *PQdatabase;

/* routines declared here */

/* routines declared elsewhere */
extern char	*getenv();
extern char	*xpgPQexec();

char *SmgrList[] = {
    "magnetic disk",
#ifdef SONY_JUKEBOX
    "sony jukebox",
#endif
#ifdef MAIN_MEMORY
    "main memory",
#endif
    (char *) NULL
};

setenv()
{}



/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
getLargeObj(name, cmd)
  char *name, *cmd;
{
    if (!fork())
    {
	isetup(PQhost, PQport, PQdatabase);
	icopy_out(name, cmd, 0);
	/* ishutdown(); ---icopy_out calls ishutdown now */
	exit(0);
    }
}




/*
main(argc, argv)
    int argc;
    char **argv;
{
    int dir;
    char *dbname;
    char *smgr;
    int smgrno;
    char *host, *port;
    char *scrfname, *destfname;
    char *curarg;
    char *src1, *destfname_out; 
    host = port = dbname = smgr = destfname = (char *) NULL;
   
    smgrno = 0;

  
    isetup("falafel", "12447", "ill");

    scrfname = "63487.tiff";
    src1= destfname = "tiff_in_db";
    destfname_out = "copy_to";
    icopy_in(scrfname, destfname, smgrno);

    
    icopy_out(src1, destfname_out, smgrno);

    ishutdown();

    exit (0);
}
*/

void
icopy_in(srcfname, destfname, smgrno)
    char *srcfname;
    char *destfname;
    int smgrno;
{
    int srcfd, destfd;
    char *buf, *lbuf;
    int nread, nwrite, totread, nbytes;
    int done;

    /* copy in cannot go to stdout */
    if (strcmp(destfname, "-") == 0)
	usage();

    if (strcmp(srcfname, "-") == 0)
	srcfd = fileno(stdin);
    else if ((srcfd = open(srcfname, O_RDONLY, 0600)) < 0) {
	perror(ProgName);
	exit (1);
    }

    if ((destfd = p_creat(destfname, INV_WRITE|smgrno, Inversion)) < 0) {
	fprintf(stderr, "Cannot create Inversion file %s\n", destfname);
	fflush(stderr);
	exit (1);
    }

    if ((buf = (char *) malloc(IBUFSIZ)) == (char *) NULL) {
	fprintf(stderr, "cannot allocate %d bytes for copy buffer\n", IBUFSIZ);
	fflush(stderr);
	exit (1);
    }

    done = FALSE;
    while (!done) {
	lbuf = buf;
	totread = 0;
	nbytes = IBUFSIZ;

	/* read one inversion file system buffer's worth of data */
	while (nbytes > 0) {
	    if ((nread = read(srcfd, lbuf, nbytes)) < 0) {
		perror(ProgName);
		exit (1);
	    } else if (nread == 0) {
		nbytes = 0;
		done = TRUE;
	    } else {
		nbytes -= nread;
		totread += nread;
		lbuf += nread;
	    }
	}

	/* write it out to the inversion file */
	lbuf = buf;
	while (totread > 0) {
	    if ((nwrite = p_write(destfd, lbuf, totread)) <= 0) {
		fprintf(stderr, "%s: write failed to Inversion file %s\n",
			ProgName, destfname);
		fflush(stderr);
		exit (1);
	    }
	    totread -= nwrite;
	    lbuf += nwrite;
	}
    }

    (void) close(srcfd);
    (void) p_close(destfd);
}

void
icopy_out(srcfname, destfname, smgrno)
    char *srcfname;
    char *destfname;
    int smgrno;
{
    int srcfd, destfd;
    char *buf, *lbuf;
    int nread, nwrite, totread, nbytes;
    int done;
    FILE *ptr;
    /* copy out cannot come from stdin */
    if (strcmp(srcfname, "-") == 0)
	usage();

    if ((srcfd = p_open(srcfname, INV_READ)) < 0) {
	fprintf(stderr, "%s: cannot open Inversion file %s\n",
		ProgName, srcfname);
	fflush(stderr);
	exit (1);
    }

    if (strcmp(destfname, "-") == 0)
	destfd = fileno(stdout);
    else if ((destfd = open(destfname, O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0) {
	perror(ProgName);
	exit (1);
    }

    if (strncmp(destfname, "|", 1) == 0 ) { 
      ptr = popen(destfname+1, "w");
      if ( ptr == NULL ) { 
	fprintf(stderr,"can't popen : %s\n" , destfname);
        fflush(stderr);
	exit (1);
      }
      destfd = fileno(ptr);
    }
	

    if ((buf = (char *) malloc(IBUFSIZ)) == (char *) NULL) {
	fprintf(stderr, "cannot allocate %d bytes for copy buffer\n", IBUFSIZ);
	fflush(stderr);
	exit (1);
    }

    done = FALSE;
    while (!done) {
	lbuf = buf;
	totread = 0;
	nbytes = IBUFSIZ;

	/* read one inversion file system buffer's worth of data */
	while (nbytes > 0) {
	    if ((nread = p_read(srcfd, lbuf, nbytes)) < 0) {
		fprintf(stderr, "%s: read failed from inversion file %s\n",
			ProgName, srcfname);
		fflush(stderr);
		exit (1);
	    } else if (nread == 0) {
		nbytes = 0;
		done = TRUE;
	    } else {
		nbytes -= nread;
		totread += nread;
		lbuf += nread;
	    }
	}

	/* write it out to the unix file */
	lbuf = buf;
	while (totread > 0) {
	    if ((nwrite = write(destfd, lbuf, totread)) <= 0) {
		perror(ProgName);
		exit (1);
	    }
	    totread -= nwrite;
	    lbuf += nwrite;
	}
    }

    (void) p_close(srcfd);
    if (strncmp(destfname, "|", 1) == 0 )
    {
	ishutdown();
	pclose(ptr);
    }
    else
	(void) close(destfd);
}

void
isetup(host, port, dbname)
    char *host;
    char *port;
    char *dbname;
{
    char *res;

/*
    PQport = port;
    PQhost = host;
    PQsetdb(dbname);
*/

    res = xpgPQexec("begin");
    if (*res == 'E') {
	fprintf(stderr, "%s: begin xact failed: %s\n", ProgName, *++res);
	fflush(stderr);
	exit (1);
    }
}

void
ishutdown()
{
    char *res;

    res = xpgPQexec("end");
    if (*res == 'E') {
	fprintf(stderr, "%s: copy failed at commit: %s\n", ProgName, *++res);
	fflush(stderr);
	exit (1);
    }
}
/*
 *  nextarg() -- getopt()-style routine to get next arg.
 *
 *	This routine returns the string beginning after the option letter
 *	in the current argument, if any, or the next argument otherwise.
 *	Argc and argv are updated as appropriate.
 */

char *
nextarg(argc_p, argv_p)
    int *argc_p;
    char ***argv_p;
{
    if (*++(**argv_p) == '\0') {
	if (--(*argc_p) == 0)
	    usage();
	    /* NOTREACHED */
	else
	    return (*++(*argv_p));
    } else
	return (**argv_p);
}

/*
 *  smgrlookup() -- Look up a storage manager by name.
 *
 *	The offsets in the storage manager table compiled into this
 *	program are the same as those used by the backend.  We rely
 *	on this fact.
 */

int
smgrlookup(smgr)
    char *smgr;
{
    int i;

    for (i = 0; SmgrList[i] != (char *) NULL; i++)
	if (strcmp(smgr, SmgrList[i]) == 0)
	    return (i);

    return (-1);
}

void
usage()
{
    int i;

    fprintf(stderr, "usage: %s {in|out} ", ProgName);
    fprintf(stderr, "-h host -p port -d db -s smgr from_file to_file\n\n");

    fprintf(stderr, "    'in' copies to Inversion, and 'out' copies from Inversion.\n\n");

    fprintf(stderr, "    smgr may be:\n");
    for (i = 0; SmgrList[i] != (char *) NULL; i++)
	fprintf(stderr, "\t%s\n", SmgrList[i]);
    fprintf(stderr, "    smgr is ignored for %s out.\n", ProgName);

    fprintf(stderr, "\n    from_file or to_file may be '-', for stdin and stdout, respectively.\n");
    fprintf(stderr, "    stdin may not be used with %s out.\n", ProgName);
    fprintf(stderr, "    stdout may not be used with %s in.\n", ProgName);

    fflush(stderr);
    exit (1);
}
