#if !NO_SCCS_STRINGS
static char sccs_maccopy_c[] = "@(#)maccopy.c	128.1 1/20/93 19:39:05";
#endif /* NO_SCCS_STRINGS */
/***********************************************************************\

   (c) Copyright 1991 by Lotus Development Corporation
   All Rights Reserved

   Module:  maccopy.c

   Description:   Custom macro command that copies ranges without changing
   relative formula references.

\************************************************************************/

#define LPI_MAIN_MODULE      /* identify this module as the primary one */ 

#define USE_REGISTER         /* incorporate routines to register macros */
#define USE_RANGE     /* incorporate routines to access Range functions */
#define USE_CELL       /* incorporate routines to access Cell functions */

#include "lpixport.h"           /* incorporate Lotus header information */

#define MACCOPY_NAME "copy"                     /* name of add-in macro */

/************************************************************************\

The following function, copy, prompts the user for a source and
target range.  Copy duplicates the contents of each cell in the
source range in the corresponding cell in the target range.  Copy
beeps if the source and target ranges have different dimensions.

\************************************************************************/

lsshort copy(RegContext, arg_count, LpiContext)
   LpiRegContextType RegContext;       /* required registration context */
   lushort arg_count;                      /* number of input arguments */
   lptr(CONTEXT) LpiContext;                        /* required context */
{

   lsshort      retval;                                  /* return code */
   lushort      i;                             /* loop counter variable */
   LpiRangeType theSourceRange;            /* source Range ADT variable */
   LpiRangeType theTargetRange;            /* target Range ADT variable */
   lsshort      theAppError;                          /* error variable */ 

   lushort      theNumSSheets;
   lushort      theNumSColumns;
   lushort      theNumSRows;                 /* source range dimensions */
   lmbcs        theSWorkfileName[LPI_RNG_FILEPATH_BUFLEN];

   lushort      theNumTSheets;
   lushort      theNumTColumns;
   lushort      theNumTRows;                 /* target range dimensions */
   lmbcs        theTWorkfileName[LPI_RNG_FILEPATH_BUFLEN];

   lushort      s, c, r;           /* range scannning for loop counters */
   LpiCellType  theCell;                           /* Cell ADT variable */
   lmbcs        theContents[LPI_CL_CELL_BUFLEN];     /* contents buffer */
   lsshort      theDataType;                          /* cell data type */
   lushort      theArgType;                       /* argument data type */

   lushort      theSFirstSheet;           /* first source cell position */
   lushort      theSFirstColumn;
   lushort      theSFirstRow;

   lushort      theTFirstSheet;           /* first target cell position */
   lushort      theTFirstColumn;
   lushort      theTFirstRow;

   /*
      Get the input values as source and target ranges.  For both
      ranges, get the first cell and dimensions.  If the ranges
      are the same size, cycle through the source range cell by
      cell.  At each cell, extract the contents, create a new cell
      at the corresponding position in the target range, and assign
      the source cell's contents to the target cell.
   */

   retval = LpiRegGetArgRange(0,&theSourceRange);   /* get source range */
   if (retval != LPI_SUCCESS) return retval;      /* confirm you got it */
   retval = LpiRegGetArgRange(1,&theTargetRange);   /* get target range */
   if (retval != LPI_SUCCESS) return retval;      /* confirm you got it */

   /* get the source range's front top left cell coordinates */
   retval = LpiRngGetFirstCell(theSourceRange, theSWorkfileName,
     &theSFirstSheet, &theSFirstColumn, &theSFirstRow);
   if (retval != LPI_SUCCESS) goto error;

   /* get number of sheets in the range */
   retval = LpiRngGetSheets(theSourceRange, &theNumSSheets);
   if (retval != LPI_SUCCESS) goto error;

   /* get number of columns in the range */
   retval = LpiRngGetColumns(theSourceRange, &theNumSColumns);
   if (retval != LPI_SUCCESS) goto error;

   /* get number of rows in the range */
   retval = LpiRngGetRows(theSourceRange, &theNumSRows);
   if (retval != LPI_SUCCESS) goto error;

   /* get the targets range's front top left cell coordinates */
   retval = LpiRngGetFirstCell(theTargetRange, theTWorkfileName,
     &theTFirstSheet, &theTFirstColumn, &theTFirstRow);
   if (retval != LPI_SUCCESS) goto error;

   /* get number of sheets in the range */
   retval = LpiRngGetSheets(theTargetRange, &theNumTSheets);
   if (retval != LPI_SUCCESS) goto error;

   /* get number of columns in the range */
   retval = LpiRngGetColumns(theTargetRange, &theNumTColumns);
   if (retval != LPI_SUCCESS) goto error;

   /* get number of rows in the range */
   retval = LpiRngGetRows(theTargetRange, &theNumTRows);
   if (retval != LPI_SUCCESS) goto error;

   /* verify same dimensions */
   if ((theNumSSheets != theNumTSheets) ||
       (theNumSColumns != theNumTColumns) ||
       (theNumSRows != theNumTRows)) {
      goto error;
   }

   theNumSSheets--;      /* decrement all three dimensions */
   theNumSColumns--;         /* to support zero-based loop */
   theNumSRows--;                     /* counter variables */

   /* loop through the range by row, column, and sheet */
   for (s = 0; s <= theNumSSheets; s++)
   {
      for (c = 0; c <= theNumSColumns; c++)
      {
         for (r = 0; r <= theNumSRows; r++)
         {
            /* construct a cell at the next source range location */
            retval = LpiClConstructWZXY(&theCell, theSWorkfileName,
               theSFirstSheet+s, theSFirstColumn+c, theSFirstRow+r);
            if (retval != LPI_SUCCESS)
            {
               LpiRngDestroy(&theSourceRange);
               LpiRngDestroy(&theTargetRange);
               goto error;
            }
      
            /* extract contents of source cell */
            retval = LpiClGetContents(theCell,theContents);
            LpiClDestroy(&theCell);
            if (retval != LPI_SUCCESS)
            {
               LpiRngDestroy(&theSourceRange);
               LpiRngDestroy(&theTargetRange);
               goto error;
            }
            /* construct a cell at same relative position in target range */
            retval = LpiClConstructWZXY(&theCell, theTWorkfileName,
               theTFirstSheet+s, theTFirstColumn+c, theTFirstRow+r);
            if (retval != LPI_SUCCESS)
            {
               LpiRngDestroy(&theSourceRange);
               LpiRngDestroy(&theTargetRange);
               goto error;
            }
      
            /* set target cell's contents to source cell's */
            retval = LpiClSetContents(theCell,theContents,&theAppError);
            LpiClDestroy(&theCell);
            if (retval != LPI_SUCCESS)
            {
               LpiRngDestroy(&theSourceRange);
               LpiRngDestroy(&theTargetRange);
               goto error;
            }
         }     
      }     
   }
   /* destroy Range objects */
   LpiRngDestroy(&theSourceRange);
   LpiRngDestroy(&theTargetRange);
   return LPI_SUCCESS;                            /* signal no problems */

error:
   /* destroy Range objects, if active */
   if (theSourceRange != LNULL) LpiRngDestroy(&theSourceRange);
   if (theTargetRange != LNULL) LpiRngDestroy(&theTargetRange);
   return LPI_SUCCESS;
}

/************************************************************************\

   The following function, LpiBind, is called the 1-2-3 loads our add-in.
   This function loads the Register module and registers our macro.
   Use this function to perform any setup, such as allocating memory,
   opening files, etc.

\************************************************************************/

LpiBind(maccopy_b)
{
   lsshort retval;                              /* function return code */
   lushort arg_types[2];        /* array of argument types, two entries */
                  
   arg_types[0] = LPI_T_ARG_TYPE_RNG;      /* first argument is a range */
   arg_types[1] = LPI_T_ARG_TYPE_RNG;     /* second argument is a range */

   LPI_SETUP_LOAD;      /* required before loading zero or more modules */

   if (LPI_LOAD_REGISTER != LPI_SUCCESS)        /* load Register module */
      LpiSignal (LPI_FAILURE);
   if (LPI_LOAD_RANGE != LPI_SUCCESS)              /* load Range module */
      LpiSignal (LPI_FAILURE);
   if (LPI_LOAD_CELL != LPI_SUCCESS)                /* load Cell module */
      LpiSignal (LPI_FAILURE);

   retval = LpiRegMacro(
      MACCOPY_NAME,                   /* macro name, in a #define above */
      copy,               /* name of function that implements the macro */
      2,                                   /* number of input arguments */
      arg_types,                       /* array of input argument types */ 
      LNULL,                                    /* registration context */
      LPI_T_REG_MAC_NO_FLAGS);       /* no special registration options */

   /* if registration fails, indicate an error */
   if (retval != LPI_SUCCESS) LpiSignal (LPI_FAILURE); 

   LpiSignal (LPI_SUCCESS);             /* otherwise indicate no errors */
}

/************************************************************************\

   The following function, LpiUnbind, is called when 1-2-3 unloads our
   add-in.  This function simply executes the macro, LPI_UNBIND and
   signals no errors.  Use this function to perform any cleanup, such as
   deallocating memory you allocated in LpiBind, closing opened files, etc.

/************************************************************************/

LpiUnbind(maccopy_u)
{
   LPI_UNLOAD;                                     /* macro for cleanup */

   LpiSignal(LPI_SUCCESS);                        /* indicate no errors */
}


