/*

-Disclaimer

   THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE
   CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S.
   GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE
   ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE
   PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS"
   TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY
   WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A
   PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC
   SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE
   SOFTWARE AND RELATED MATERIALS, HOWEVER USED.

   IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA
   BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT
   LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND,
   INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS,
   REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE
   REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY.

   RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF
   THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY
   CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE
   ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE.

*/

/*
 CSPICE private macro file.

-Particulars

   Current list of macros (spelling counts)

     BLANK
     C2F_MAP_CELL
     C2F_MAP_CELL2
     C2F_MAP_CELL3
     CELLINIT
     CELLINIT2
     CELLINIT3
     CELLISSETCHK
     CELLISSETCHK2
     CELLISSETCHK2_VAL
     CELLISSETCHK3
     CELLISSETCHK3_VAL
     CELLISSETCHK_VAL
     CELLMATCH2
     CELLMATCH2_VAL
     CELLMATCH3
     CELLMATCH3_VAL
     CELLTYPECHK
     CELLTYPECHK2
     CELLTYPECHK2_VAL
     CELLTYPECHK3
     CELLTYPECHK3_VAL
     CELLTYPECHK_VAL
     CHKFSTR
     CHKFSTR_VAL
     CHKOSTR
     CHKOSTR_VAL
     CHKPTR
     Constants
     Even
     F2C_MAP_CELL
     Index values
     MOVED
     MOVEI
     MaxAbs
     MaxVal
     MinAbs
     MinVal
     Odd
     SpiceError
     TolOrFail

-Restrictions

   This is a private macro file for use within CSPICE.
   Do not use or alter any entry.  Or else!

-Author_and_Institution

   N.J. Bachman    (JPL)
   E.D. Wright     (JPL)

-Version

   -CSPICE Version 4.3.0, 18-SEP-2013   (NJB)

      Bug fix: missing comma was added to argument list
      in body of macro CELLTYPECHK3_VAL.

   -CSPICE Version 4.2.0, 16-FEB-2005   (NJB)

      Bug fix:  in the macro C2F_MAP_CELL, error checking has been
      added after the sequence of calls to ssizec_ and scardc_.
      If either of these routines signals an error, the dynamically
      allocated memory for the "Fortran cell" is freed.

   -CSPICE Version 4.1.0, 06-DEC-2002   (NJB)

      Bug fix:  added previous missing, bracketing parentheses to
      references to input cell pointer argument in macro
      CELLINIT.

      Changed CELLINIT macro so it no longer initializes to zero
      length all strings in data array of a character cell.  Instead,
      strings are terminated with a null in their final element.

   -CSPICE Version 4.0.0, 22-AUG-2002   (NJB)

       Added macro definitions to support CSPICE cells and sets:

          C2F_MAP_CELL
          C2F_MAP_CELL2
          C2F_MAP_CELL3
          CELLINIT
          CELLINIT2
          CELLINIT3
          CELLISSETCHK
          CELLISSETCHK2
          CELLISSETCHK2_VAL
          CELLISSETCHK3
          CELLISSETCHK3_VAL
          CELLISSETCHK_VAL
          CELLMATCH2
          CELLMATCH2_VAL
          CELLMATCH3
          CELLMATCH3_VAL
          CELLTYPECHK
          CELLTYPECHK2
          CELLTYPECHK2_VAL
          CELLTYPECHK3
          CELLTYPECHK3_VAL
          CELLTYPECHK_VAL
          F2C_MAP_CELL

   -CSPICE Version 3.0.0, 09-JAN-1998   (NJB)

       Added output string check macros CHKOSTR and CHKOSTR_VAL.
       Removed variable name arguments from macros

          CHKPTR
          CHKPTR_VAL
          CHKFSTR
          CHKRSTR_VAL

       The strings containing names of the checked variables are now
       generated from the variables themselves via the # operator.

   -CSPICE Version 2.0.0, 03-DEC-1997   (NJB)

       Added pointer check macro CHKPTR and Fortran string check macro
       CHKFSTR.

   -CSPICE Version 1.0.0, 25-OCT-1997   (EDW)
*/

#include "SpiceZdf.h"
#include <math.h>
#include <string.h>

#define MOVED(arrfrm, ndim, arrto) (memmove((void *)(arrto), (void *)(arrfrm), sizeof(SpiceDouble) * (ndim)))

#define MOVEI(arrfrm, ndim, arrto) (memmove((void *)(arrto), (void *)(arrfrm), sizeof(SpiceInt) * (ndim)))

/*
Define a tolerance test for those pesky double precision reals.
True if the difference is less than the tolerance, false otherwise.
The tolerance refers to a percentage. x, y and tol should be declared
double.  All values are assumed to be non-zero.  Okay?
*/

#define TolOrFail(x, y, tol) (fabs(x - y) < (tol * fabs(x)))

/*
Simple error output through standard SPICE error system .  Set the error
message and the type
*/

#define SpiceError(errmsg, errtype)                                                                                    \
                                                                                                                       \
    {                                                                                                                  \
        setmsg_c(errmsg);                                                                                              \
        sigerr_c(errtype);                                                                                             \
    }

/*
Return a value which is the maximum/minimum of the absolute values of
two values.
*/

#define MaxAbs(a, b) (fabs(a) >= fabs(b) ? fabs(a) : fabs(b))
#define MinAbs(a, b) (fabs(a) < fabs(b) ? fabs(a) : fabs(b))

/*
Return a value which is the maximum/minimum value of two values.
*/

#define MaxVal(A, B) ((A) >= (B) ? (A) : (B))
#define MinVal(A, B) ((A) < (B) ? (A) : (B))

/*
Determine whether a value is even or odd
*/
#define Even(x) (((x)&1) == 0)
#define Odd (x)(((x)&1) != 0)

/*
Array indexes for vectors.
*/

#define SpiceX 0
#define SpiceY 1
#define SpiceZ 2
#define SpiceVx 3
#define SpiceVy 4
#define SpiceVz 5

/*
Physical constants and dates.
*/

#define B1900 2415020.31352
#define J1900 2415020.0
#define JYEAR 31557600.0
#define TYEAR 31556925.9747
#define J1950 2433282.5
#define SPD 86400.0
#define B1950 2433282.42345905
#define J2100 2488070.0
#define CLIGHT 299792.458
#define J2000 2451545.0

/*
Common literal values.
*/

#define NULLCHAR ((SpiceChar)0)
#define NULLCPTR ((SpiceChar *)0)
#define BLANK ((SpiceChar)' ')

/*
Macro CHKPTR is used for checking for a null pointer.  CHKPTR uses
the constants

   CHK_STANDARD
   CHK_DISCOVER
   CHK_REMAIN

to control tracing behavior.  Values  and meanings are:

   CHK_STANDARD          Standard tracing.  If an error
                         is found, signal it, check out
                         and return.

   CHK_DISCOVER          Discovery check-in.  If an
                         error is found, check in, signal
                         the error, check out, and return.

   CHK_REMAIN            If an error is found, signal it.
                         Do not check out or return.  This
                         would allow the caller to clean up
                         before returning, if necessary.
                         In such cases the caller must test
                         failed_c() after the macro call.

CHKPTR should be used in void functions.  In non-void functions,
use CHKPTR_VAL, which is defined below.

*/

#define CHK_STANDARD 1
#define CHK_DISCOVER 2
#define CHK_REMAIN 3

#define CHKPTR(errHandling, modname, pointer)                                                                          \
                                                                                                                       \
    if ((void *)(pointer) == (void *)0) {                                                                              \
        if ((errHandling) == CHK_DISCOVER) {                                                                           \
            chkin_c(modname);                                                                                          \
        }                                                                                                              \
                                                                                                                       \
        setmsg_c("Pointer \"#\" is null; a non-null "                                                                  \
                 "pointer is required.");                                                                              \
        errch_c("#", (#pointer));                                                                                      \
        sigerr_c("SPICE(NULLPOINTER)");                                                                                \
                                                                                                                       \
        if (((errHandling) == CHK_DISCOVER) || ((errHandling) == CHK_STANDARD)) {                                      \
            chkout_c(modname);                                                                                         \
            return;                                                                                                    \
        }                                                                                                              \
    }

#define CHKPTR_VAL(errHandling, modname, pointer, retval)                                                              \
                                                                                                                       \
    if ((void *)(pointer) == (void *)0) {                                                                              \
        if ((errHandling) == CHK_DISCOVER) {                                                                           \
            chkin_c(modname);                                                                                          \
        }                                                                                                              \
                                                                                                                       \
        setmsg_c("Pointer \"#\" is null; a non-null "                                                                  \
                 "pointer is required.");                                                                              \
        errch_c("#", (#pointer));                                                                                      \
        sigerr_c("SPICE(NULLPOINTER)");                                                                                \
                                                                                                                       \
        if (((errHandling) == CHK_DISCOVER) || ((errHandling) == CHK_STANDARD)) {                                      \
            chkout_c(modname);                                                                                         \
            return (retval);                                                                                           \
        }                                                                                                              \
    }

/*
Macro CHKFSTR checks strings that are to be passed to Fortran or
f2c'd Fortran routines.  Such strings must have non-zero length,
and their pointers must be non-null.

CHKFSTR should be used in void functions.  In non-void functions,
use CHKFSTR_VAL, which is defined below.
*/

#define CHKFSTR(errHandling, modname, string)                                                                          \
                                                                                                                       \
    CHKPTR(errHandling, modname, string);                                                                              \
                                                                                                                       \
    if (((void *)string != (void *)0) && (strlen(string) == 0)) {                                                      \
        if ((errHandling) == CHK_DISCOVER) {                                                                           \
            chkin_c(modname);                                                                                          \
        }                                                                                                              \
                                                                                                                       \
        setmsg_c("String \"#\" has length zero.");                                                                     \
        errch_c("#", (#string));                                                                                       \
        sigerr_c("SPICE(EMPTYSTRING)");                                                                                \
                                                                                                                       \
        if (((errHandling) == CHK_DISCOVER) || ((errHandling) == CHK_STANDARD)) {                                      \
            chkout_c(modname);                                                                                         \
            return;                                                                                                    \
        }                                                                                                              \
    }

#define CHKFSTR_VAL(errHandling, modname, string, retval)                                                              \
                                                                                                                       \
    CHKPTR_VAL(errHandling, modname, string, retval);                                                                  \
                                                                                                                       \
    if (((void *)string != (void *)0) && (strlen(string) == 0)) {                                                      \
        if ((errHandling) == CHK_DISCOVER) {                                                                           \
            chkin_c(modname);                                                                                          \
        }                                                                                                              \
                                                                                                                       \
        setmsg_c("String \"#\" has length zero.");                                                                     \
        errch_c("#", (#string));                                                                                       \
        sigerr_c("SPICE(EMPTYSTRING)");                                                                                \
                                                                                                                       \
        if (((errHandling) == CHK_DISCOVER) || ((errHandling) == CHK_STANDARD)) {                                      \
            chkout_c(modname);                                                                                         \
            return (retval);                                                                                           \
        }                                                                                                              \
    }

/*
Macro CHKOSTR checks output string pointers and the associated
string length values supplied as input arguments.  Output string
pointers must be non-null, and the string lengths must be at
least 2, so Fortran routine can write at least one character to
the output string, and so a null terminator can be appended.
CHKOSTR should be used in void functions.  In non-void functions,
use CHKOSTR_VAL, which is defined below.
*/

#define CHKOSTR(errHandling, modname, string, length)                                                                  \
                                                                                                                       \
    CHKPTR(errHandling, modname, string);                                                                              \
                                                                                                                       \
    if (((void *)string != (void *)0) && (length < 2)) {                                                               \
        if ((errHandling) == CHK_DISCOVER) {                                                                           \
            chkin_c(modname);                                                                                          \
        }                                                                                                              \
                                                                                                                       \
        setmsg_c("String \"#\" has length #; must be >= 2.");                                                          \
        errch_c("#", (#string));                                                                                       \
        errint_c("#", (length));                                                                                       \
        sigerr_c("SPICE(STRINGTOOSHORT)");                                                                             \
                                                                                                                       \
        if (((errHandling) == CHK_DISCOVER) || ((errHandling) == CHK_STANDARD)) {                                      \
            chkout_c(modname);                                                                                         \
            return;                                                                                                    \
        }                                                                                                              \
    }

#define CHKOSTR_VAL(errHandling, modname, string, length, retval)                                                      \
                                                                                                                       \
    CHKPTR_VAL(errHandling, modname, string, retval);                                                                  \
                                                                                                                       \
    if (((void *)string != (void *)0) && (length < 2)) {                                                               \
        if ((errHandling) == CHK_DISCOVER) {                                                                           \
            chkin_c(modname);                                                                                          \
        }                                                                                                              \
                                                                                                                       \
        setmsg_c("String \"#\" has length #; must be >= 2.");                                                          \
        errch_c("#", (#string));                                                                                       \
        errint_c("#", (length));                                                                                       \
        sigerr_c("SPICE(STRINGTOOSHORT)");                                                                             \
                                                                                                                       \
        if (((errHandling) == CHK_DISCOVER) || ((errHandling) == CHK_STANDARD)) {                                      \
            chkout_c(modname);                                                                                         \
            return (retval);                                                                                           \
        }                                                                                                              \
    }

/*
Definitions for Cells and Sets
*/

/*
Cell initialization macros
*/
#define CELLINIT(cellPtr)                                                                                              \
                                                                                                                       \
    if (!((cellPtr)->init)) {                                                                                          \
        if ((cellPtr)->dtype == SPICE_CHR) {                                                                           \
            /*                                                                                                         \
            Make sure all elements of the data array, including                                                        \
            the control area, start off null-terminated.  We place                                                     \
            the null character in the final element of each string,                                                    \
            so as to avoid wiping out data that may have been                                                          \
            assigned to the data array prior to initialization.                                                        \
            */                                                                                                         \
            SpiceChar *sPtr;                                                                                           \
            SpiceInt i;                                                                                                \
            SpiceInt nmax;                                                                                             \
                                                                                                                       \
            nmax = SPICE_CELL_CTRLSZ + (cellPtr)->size;                                                                \
                                                                                                                       \
            for (i = 1; i <= nmax; i++) {                                                                              \
                sPtr = (SpiceChar *)((cellPtr)->base) + i * (cellPtr)->length - 1;                                     \
                                                                                                                       \
                *sPtr = NULLCHAR;                                                                                      \
            }                                                                                                          \
        } else {                                                                                                       \
            zzsynccl_c(C2F, (cellPtr));                                                                                \
        }                                                                                                              \
                                                                                                                       \
        (cellPtr)->init = SPICETRUE;                                                                                   \
    }

#define CELLINIT2(cellPtr1, cellPtr2)                                                                                  \
                                                                                                                       \
    CELLINIT(cellPtr1);                                                                                                \
    CELLINIT(cellPtr2);

#define CELLINIT3(cellPtr1, cellPtr2, cellPtr3)                                                                        \
                                                                                                                       \
    CELLINIT(cellPtr1);                                                                                                \
    CELLINIT(cellPtr2);                                                                                                \
    CELLINIT(cellPtr3);

/*
Data type checking macros:
*/
#define CELLTYPECHK(errHandling, modname, dType, cellPtr1)                                                             \
                                                                                                                       \
    if ((cellPtr1)->dtype != (dType)) {                                                                                \
        SpiceChar *typstr[3] = {"character", "double precision", "integer"};                                           \
                                                                                                                       \
        if ((errHandling) == CHK_DISCOVER) {                                                                           \
            chkin_c(modname);                                                                                          \
        }                                                                                                              \
                                                                                                                       \
        setmsg_c("Data type of # is #; expected type "                                                                 \
                 "is #.");                                                                                             \
        errch_c("#", (#cellPtr1));                                                                                     \
        errch_c("#", typstr[(cellPtr1)->dtype]);                                                                       \
        errch_c("#", typstr[dType]);                                                                                   \
        sigerr_c("SPICE(TYPEMISMATCH)");                                                                               \
                                                                                                                       \
        if (((errHandling) == CHK_DISCOVER) || ((errHandling) == CHK_STANDARD)) {                                      \
            chkout_c(modname);                                                                                         \
            return;                                                                                                    \
        }                                                                                                              \
    }

#define CELLTYPECHK_VAL(errHandling, modname, dType, cellPtr1, retval)                                                 \
                                                                                                                       \
    if ((cellPtr1)->dtype != (dType)) {                                                                                \
        SpiceChar *typstr[3] = {"character", "double precision", "integer"};                                           \
                                                                                                                       \
        if ((errHandling) == CHK_DISCOVER) {                                                                           \
            chkin_c(modname);                                                                                          \
        }                                                                                                              \
                                                                                                                       \
        setmsg_c("Data type of # is #; expected type "                                                                 \
                 "is #.");                                                                                             \
        errch_c("#", (#cellPtr1));                                                                                     \
        errch_c("#", typstr[(cellPtr1)->dtype]);                                                                       \
        errch_c("#", typstr[dType]);                                                                                   \
        sigerr_c("SPICE(TYPEMISMATCH)");                                                                               \
                                                                                                                       \
        if (((errHandling) == CHK_DISCOVER) || ((errHandling) == CHK_STANDARD)) {                                      \
            chkout_c(modname);                                                                                         \
            return (retval);                                                                                           \
        }                                                                                                              \
    }

#define CELLTYPECHK2(errHandling, modname, dtype, cellPtr1, cellPtr2)                                                  \
                                                                                                                       \
    CELLTYPECHK(errHandling, modname, dtype, cellPtr1);                                                                \
    CELLTYPECHK(errHandling, modname, dtype, cellPtr2);

#define CELLTYPECHK2_VAL(errHandling, modname, dtype, cellPtr1, cellPtr2, retval)                                      \
                                                                                                                       \
    CELLTYPECHK_VAL(errHandling, modname, dtype, cellPtr1, retval);                                                    \
    CELLTYPECHK_VAL(errHandling, modname, dtype, cellPtr2, retval);

#define CELLTYPECHK3(errHandling, modname, dtype, cellPtr1, cellPtr2, cellPtr3)                                        \
                                                                                                                       \
    CELLTYPECHK(errHandling, modname, dtype, cellPtr1);                                                                \
    CELLTYPECHK(errHandling, modname, dtype, cellPtr2);                                                                \
    CELLTYPECHK(errHandling, modname, dtype, cellPtr3);

#define CELLTYPECHK3_VAL(errHandling, modname, dtype, cellPtr1, cellPtr2, cellPtr3, retval)                            \
                                                                                                                       \
    CELLTYPECHK_VAL(errHandling, modname, dtype, cellPtr1, retval);                                                    \
    CELLTYPECHK_VAL(errHandling, modname, dtype, cellPtr2, retval);                                                    \
    CELLTYPECHK_VAL(errHandling, modname, dtype, cellPtr3, retval);

#define CELLMATCH2(errHandling, modname, cellPtr1, cellPtr2)                                                           \
                                                                                                                       \
    if ((cellPtr1)->dtype != (cellPtr2)->dtype) {                                                                      \
        SpiceChar *typstr[3] = {"character", "double precision", "integer"};                                           \
                                                                                                                       \
        if ((errHandling) == CHK_DISCOVER) {                                                                           \
            chkin_c(modname);                                                                                          \
        }                                                                                                              \
                                                                                                                       \
        setmsg_c("Data type of # is #; data type of # "                                                                \
                 "is #, but types must match.");                                                                       \
        errch_c("#", (#cellPtr1));                                                                                     \
        errch_c("#", typstr[(cellPtr1)->dtype]);                                                                       \
        errch_c("#", (#cellPtr2));                                                                                     \
        errch_c("#", typstr[(cellPtr2)->dtype]);                                                                       \
        sigerr_c("SPICE(TYPEMISMATCH)");                                                                               \
                                                                                                                       \
        if (((errHandling) == CHK_DISCOVER) || ((errHandling) == CHK_STANDARD)) {                                      \
            chkout_c(modname);                                                                                         \
            return;                                                                                                    \
        }                                                                                                              \
    }

#define CELLMATCH2_VAL(errHandling, modname, cellPtr1, cellPtr2, retval)                                               \
                                                                                                                       \
    if ((cellPtr1)->dtype != (cellPtr2)->dtype) {                                                                      \
        SpiceChar *typstr[3] = {"character", "double precision", "integer"};                                           \
                                                                                                                       \
        if ((errHandling) == CHK_DISCOVER) {                                                                           \
            chkin_c(modname);                                                                                          \
        }                                                                                                              \
                                                                                                                       \
        setmsg_c("Data type of # is #; data type of # "                                                                \
                 "is #, but types must match.");                                                                       \
        errch_c("#", (#cellPtr1));                                                                                     \
        errch_c("#", typstr[(cellPtr1)->dtype]);                                                                       \
        errch_c("#", (#cellPtr2));                                                                                     \
        errch_c("#", typstr[(cellPtr2)->dtype]);                                                                       \
        sigerr_c("SPICE(TYPEMISMATCH)");                                                                               \
                                                                                                                       \
        if (((errHandling) == CHK_DISCOVER) || ((errHandling) == CHK_STANDARD)) {                                      \
            chkout_c(modname);                                                                                         \
            return (retval);                                                                                           \
        }                                                                                                              \
    }

#define CELLMATCH3(errHandling, modname, cellPtr1, cellPtr2, cellPtr3)                                                 \
                                                                                                                       \
    CELLMATCH2(errHandling, modname, cellPtr1, cellPtr2);                                                              \
    CELLMATCH2(errHandling, modname, cellPtr2, cellPtr3);

#define CELLMATCH3_VAL(errHandling, modname, cellPtr1, cellPtr2, cellPtr3, retval)                                     \
                                                                                                                       \
    CELLMATCH2_VAL(errHandling, modname, cellPtr1, cellPtr2, retval);                                                  \
                                                                                                                       \
    CELLMATCH2_VAL(errHandling, modname, cellPtr2, cellPtr3, retval);

/*
Set checking macros:
*/
#define CELLISSETCHK(errHandling, modname, cellPtr1)                                                                   \
                                                                                                                       \
    if (!(cellPtr1)->isSet) {                                                                                          \
        if ((errHandling) == CHK_DISCOVER) {                                                                           \
            chkin_c(modname);                                                                                          \
        }                                                                                                              \
                                                                                                                       \
        setmsg_c("Cell # must be sorted and have unique "                                                              \
                 "values in order to be a CSPICE set. "                                                                \
                 "The isSet flag in this cell is SPICEFALSE, "                                                         \
                 "indicating the cell may have been modified "                                                         \
                 "by a routine that doesn't preserve these "                                                           \
                 "properties.");                                                                                       \
        errch_c("#", (#cellPtr1));                                                                                     \
        sigerr_c("SPICE(NOTASET)");                                                                                    \
                                                                                                                       \
        if (((errHandling) == CHK_DISCOVER) || ((errHandling) == CHK_STANDARD)) {                                      \
            chkout_c(modname);                                                                                         \
            return;                                                                                                    \
        }                                                                                                              \
    }

#define CELLISSETCHK_VAL(errHandling, modname, cellPtr1, retval)                                                       \
                                                                                                                       \
    if (!(cellPtr1)->isSet) {                                                                                          \
        if ((errHandling) == CHK_DISCOVER) {                                                                           \
            chkin_c(modname);                                                                                          \
        }                                                                                                              \
                                                                                                                       \
        setmsg_c("Cell # must be sorted and have unique "                                                              \
                 "values in order to be a CSPICE set. "                                                                \
                 "The isSet flag in this cell is SPICEFALSE, "                                                         \
                 "indicating the cell may have been modified "                                                         \
                 "by a routine that doesn't preserve these "                                                           \
                 "properties.");                                                                                       \
        errch_c("#", (#cellPtr1));                                                                                     \
        sigerr_c("SPICE(NOTASET)");                                                                                    \
                                                                                                                       \
        if (((errHandling) == CHK_DISCOVER) || ((errHandling) == CHK_STANDARD)) {                                      \
            chkout_c(modname);                                                                                         \
            return (retval);                                                                                           \
        }                                                                                                              \
    }

#define CELLISSETCHK2(errHandling, modname, cellPtr1, cellPtr2)                                                        \
                                                                                                                       \
    CELLISSETCHK(errHandling, modname, cellPtr1);                                                                      \
    CELLISSETCHK(errHandling, modname, cellPtr2);

#define CELLISSETCHK2_VAL(errHandling, modname, cellPtr1, cellPtr2, retval)                                            \
                                                                                                                       \
    CELLISSETCHK_VAL(errHandling, modname, cellPtr1, retval);                                                          \
    CELLISSETCHK_VAL(errHandling, modname, cellPtr2, retval);

#define CELLISSETCHK3(errHandling, modname, cellPtr1, cellPtr2, cellPtr3)                                              \
                                                                                                                       \
    CELLISSETCHK(errHandling, modname, cellPtr1);                                                                      \
    CELLISSETCHK(errHandling, modname, cellPtr2);                                                                      \
    CELLISSETCHK(errHandling, modname, cellPtr3);

#define CELLISSETCHK3_VAL(errHandling, modname, cellPtr1, cellPtr2, cellPtr3, retval)                                  \
                                                                                                                       \
    CELLISSETCHK_VAL(errHandling, modname, cellPtr1, retval);                                                          \
    CELLISSETCHK_VAL(errHandling, modname, cellPtr2, retval);                                                          \
    CELLISSETCHK_VAL(errHandling, modname, cellPtr3, retval);

/*
C-to-Fortran and Fortran-to-C character cell translation macros:
*/

/*
Macros that map one or more character C cells to dynamically
allocated Fortran-style character cells:
*/
#define C2F_MAP_CELL(caller, CCell, fCell, fLen)                                                                       \
                                                                                                                       \
    {                                                                                                                  \
        /*                                                                                                             \
        fCell and fLen are to be passed by reference, as if this                                                       \
        macro were a function.                                      \                                                  \
                                                                                                                       \
                                                                                                                       \
        Caution: dynamically allocates array fCell, which is to be                                                     \
        freed by caller!                                                                                               \
        */                                                                                                             \
        SpiceInt ndim;                                                                                                 \
        SpiceInt lenvals;                                                                                              \
                                                                                                                       \
        ndim = (CCell)->size + SPICE_CELL_CTRLSZ;                                                                      \
        lenvals = (CCell)->length;                                                                                     \
                                                                                                                       \
        C2F_MapFixStrArr((caller), ndim, lenvals, (CCell)->base, (fLen), (fCell));                                     \
                                                                                                                       \
        if (!failed_c()) {                                                                                             \
            /*                                                                                                         \
            Explicitly set the control area info in the Fortran cell.                                                  \
            */                                                                                                         \
            ssizec_((integer *)&((CCell)->size), (char *)*(fCell), (ftnlen) * (fLen));                                 \
                                                                                                                       \
            scardc_((integer *)&((CCell)->card), (char *)*(fCell), (ftnlen) * (fLen));                                 \
                                                                                                                       \
            if (failed_c()) {                                                                                          \
                /*                                                                                                     \
                Setting size or cardinality of the Fortran cell                                                        \
                can fail, for example if the cell's string length                                                      \
                is too short.                                                                                          \
                */                                                                                                     \
                free(*(fCell));                                                                                        \
            }                                                                                                          \
        }                                                                                                              \
    }

#define C2F_MAP_CELL2(caller, CCell1, fCell1, fLen1, CCell2, fCell2, fLen2)                                            \
                                                                                                                       \
    {                                                                                                                  \
        C2F_MAP_CELL(caller, CCell1, fCell1, fLen1);                                                                   \
                                                                                                                       \
        if (!failed_c()) {                                                                                             \
            C2F_MAP_CELL(caller, CCell2, fCell2, fLen2);                                                               \
                                                                                                                       \
            if (failed_c()) {                                                                                          \
                free(*(fCell1));                                                                                       \
            }                                                                                                          \
        }                                                                                                              \
    }

#define C2F_MAP_CELL3(caller, CCell1, fCell1, fLen1, CCell2, fCell2, fLen2, CCell3, fCell3, fLen3)                     \
                                                                                                                       \
    {                                                                                                                  \
        C2F_MAP_CELL2(caller, CCell1, fCell1, fLen1, CCell2, fCell2, fLen2);                                           \
                                                                                                                       \
        if (!failed_c()) {                                                                                             \
            C2F_MAP_CELL(caller, CCell3, fCell3, fLen3);                                                               \
                                                                                                                       \
            if (failed_c()) {                                                                                          \
                free(*(fCell1));                                                                                       \
                free(*(fCell2));                                                                                       \
            }                                                                                                          \
        }                                                                                                              \
    }

/*
Macro that maps a Fortran-style character cell to a C cell
(Note: this macro frees the Fortran cell):
*/

#define F2C_MAP_CELL(fCell, fLen, CCell)                                                                               \
                                                                                                                       \
    {                                                                                                                  \
        SpiceInt card;                                                                                                 \
        SpiceInt lenvals;                                                                                              \
        SpiceInt ndim;                                                                                                 \
        SpiceInt nBytes;                                                                                               \
        SpiceInt size;                                                                                                 \
        void *array;                                                                                                   \
                                                                                                                       \
        ndim = (CCell)->size + SPICE_CELL_CTRLSZ;                                                                      \
        lenvals = (CCell)->length;                                                                                     \
        array = (CCell)->base;                                                                                         \
                                                                                                                       \
        /*                                                                                                             \
        Capture the size and cardinality of the Fortran cell.                                                          \
        */                                                                                                             \
        if (!failed_c()) {                                                                                             \
            size = sizec_((char *)(fCell), (ftnlen)fLen);                                                              \
                                                                                                                       \
            card = cardc_((char *)(fCell), (ftnlen)fLen);                                                              \
        }                                                                                                              \
                                                                                                                       \
        /*                                                                                                             \
        Copy the Fortran array into the output array.                                                                  \
        */                                                                                                             \
                                                                                                                       \
        nBytes = ndim * fLen * sizeof(SpiceChar);                                                                      \
        memmove(array, fCell, nBytes);                                                                                 \
        /*                                                                                                             \
        Convert the output array from Fortran to C style.                                                              \
        */                                                                                                             \
        F2C_ConvertTrStrArr(ndim, lenvals, (SpiceChar *)array);                                                        \
                                                                                                                       \
        /*                                                                                                             \
        Sync the size and cardinality of the C cell.                                                                   \
        */                                                                                                             \
        if (!failed_c()) {                                                                                             \
            (CCell)->size = size;                                                                                      \
            (CCell)->card = card;                                                                                      \
        }                                                                                                              \
    }

/*
   End of header SpiceZmc.h
*/
