From a39f433527af85e8b8e9593a239fee5ee56bfcf9 Mon Sep 17 00:00:00 2001 From: Chris Piker Date: Fri, 2 Aug 2024 00:08:33 -0500 Subject: [PATCH] Beginning das3_rotate --- buildfiles/Linux.mak | 1 + das2/defs.h | 3 +- das2/send.c | 14 +- das2/spice.c | 35 +++-- das2/util.c | 56 ++++++++ das2/util.h | 56 ++++++++ utilities/das3_cdf.c | 110 +++++----------- utilities/das3_rotate.c | 281 ++++++++++++++++++++++++++++++++++++++++ 8 files changed, 462 insertions(+), 94 deletions(-) create mode 100644 utilities/das3_rotate.c diff --git a/buildfiles/Linux.mak b/buildfiles/Linux.mak index 2e19bd6..82eaeb2 100644 --- a/buildfiles/Linux.mak +++ b/buildfiles/Linux.mak @@ -38,6 +38,7 @@ TEST_PROGS:=TestUnits TestArray TestVariable LoadStream TestBuilder \ CDF_PROGS:=das3_cdf ifeq ($(SPICE),yes) +UTIL_PROGS:=$(UTIL_PROGS) das3_rotate TEST_PROGS:=$(TEST_PROGS) TestSpice endif diff --git a/das2/defs.h b/das2/defs.h index 0e5f688..8e93027 100644 --- a/das2/defs.h +++ b/das2/defs.h @@ -208,7 +208,8 @@ typedef int DasErrCode; #define DASERR_VEC 40 #define DASERR_SERIAL 41 #define DASERR_ITER 42 -#define DASERR_MAX 42 +#define DASERR_SPICE 43 +#define DASERR_MAX 43 #ifdef __cplusplus } diff --git a/das2/send.c b/das2/send.c index 41a2153..6b332bf 100644 --- a/das2/send.c +++ b/das2/send.c @@ -78,7 +78,7 @@ int das_send_nodata(int nDasVer, const char* sFmt, ...) snprintf(sOut, 1151, "\n", sMsgEsc); - printf("[xx]%06zu%s", strlen(sOut), sOut); + printf("[XX]%06zu%s", strlen(sOut), sOut); } return 0; } @@ -101,7 +101,7 @@ int das_send_queryerr(int nDasVer, const char* sFmt, ...) snprintf(sOut, 1151, "\n", sMsgEsc); - printf("[xx]%06zu%s", strlen(sOut), sOut); + printf("[XX]%06zu%s", strlen(sOut), sOut); } return 47; } @@ -125,7 +125,7 @@ int das_vsend_queryerr(int nDasVer, const char* sFmt, va_list argp) snprintf(sOut, 1151, "\n", sMsgEsc); - printf("[xx]%06zu%s", strlen(sOut), sOut); + printf("[XX]%06zu%s", strlen(sOut), sOut); } return 47; } @@ -147,7 +147,7 @@ int das_send_srverr(int nDasVer, const char* sFmt, ...) snprintf(sOut, 1151, "\n", sMsgEsc); - printf("[xx]%06zu%s", strlen(sOut), sOut); + printf("[XX]%06zu%s", strlen(sOut), sOut); } return 48; } @@ -173,7 +173,7 @@ void das_send_msg(int nDasVer, const char* sSource, const char* sFmt, ...) " source=\"%s\"\n" " value=\"%s\" />\n", sSrcEsc, sMsgEsc); - printf("[xx]%06zu%s", strlen(sOut), sOut); + printf("[XX]%06zu%s", strlen(sOut), sOut); } } @@ -196,7 +196,7 @@ void das_send_progbeg(int nDasVer, const char* sSrc, double fBeg, double fEnd) char sMsg[1024] = {'\0'}; snprintf(sMsg, 1023, "\n", sSrc); - printf("[xx]%06zu%s", strlen(sMsg), sMsg); + printf("[XX]%06zu%s", strlen(sMsg), sMsg); } void das_send_progup( @@ -214,7 +214,7 @@ void das_send_progup( char sMsg[1024] = {'\0'}; snprintf(sMsg, 1023, "\n", nProg, sSrc); - printf("[xx]%06zu%s", strlen(sMsg), sMsg); + printf("[XX]%06zu%s", strlen(sMsg), sMsg); g_nLastProg = nProg; } diff --git a/das2/spice.c b/das2/spice.c index b5e80e2..fd64c64 100644 --- a/das2/spice.c +++ b/das2/spice.c @@ -5,6 +5,8 @@ #include +#include "defs.h" +#include "util.h" #include "send.h" void das_spice_err_setup() @@ -45,17 +47,32 @@ int das_send_spice_err(int nDasVer, const char* sErrType) fprintf(stderr, "ERROR: %s\n", sMsg); - if(nDasVer == 2){ - _das_escape_xml(sMsgEsc, 2047, sMsg); - snprintf(sOut, 3071, - "\n", sErrType, sMsgEsc - ); - printf("[xx]%06zu%s", strlen(sOut), sOut); + if(nDasVer > 1){ + _das_escape_xml(sMsgEsc, 2047, sMsg); + + if(nDasVer == 2){ + + snprintf(sOut, 3071, + "\n", sErrType, sMsgEsc + ); + printf("[XX]%06zu%s", strlen(sOut), sOut); + } + else{ + if(nDasVer == 3){ + snprintf(sOut, 3071, + "\n" + "%s\n" + "\n", sErrType, sMsgEsc + ); + printf("[XX]%06zu%s", strlen(sOut), sOut); + } + } + das_error(DASERR_SPICE, "Unknown stream version %d", nDasVer); } - return 89; + return DASERR_SPICE; } int das_print_spice_error(const char* sProgName) @@ -78,5 +95,5 @@ int das_print_spice_error(const char* sProgName) if(sProgName) fprintf(stderr, "ERROR (%s): %s\n", sProgName, sMsg); else fprintf(stderr, "ERROR: %s\n", sMsg); - return 89; + return DASERR_SPICE; } \ No newline at end of file diff --git a/das2/util.c b/das2/util.c index 395e27f..38fea96 100644 --- a/das2/util.c +++ b/das2/util.c @@ -950,3 +950,59 @@ double das_strtod_c(const char *nptr, char **endptr){ } #endif + +/* ************************************************************************* */ +/* Command line helps */ + +/* See a given string matches the short or long form of an argument */ +bool dascmd_isArg( + const char* sArg, const char* sShort, const char* sLong, bool* pLong +){ + if(strcmp(sArg, sShort) == 0){ + if(pLong) *pLong = false; + return true; + } + size_t uLen = strlen(sLong); /* Include the '=' */ + + if(strncmp(sArg, sLong, uLen) == 0){ + if(pLong) *pLong = true; + return true; + } + return false; +} + +/* Get the value of an argument if the current entry in argv matches + * either the short or long form */ + +bool dascmd_getArgVal( + char* sDest, size_t uDest, char** argv, int argc, int* pArgIdx, + const char* sShort, const char* sLong +){ + bool bIsLong = false; + + if(! dascmd_isArg(argv[*pArgIdx], sShort, sLong, &bIsLong)) + return false; + + const char* sVal; + if(bIsLong){ + size_t uLongSz = strlen(sLong); + if(argv[*pArgIdx][uLongSz] == '\0') /* Nothing in str after prefix */ + goto NO_ARG; + + sVal = argv[*pArgIdx] + uLongSz; + } + else{ + if(*pArgIdx > argc-2) /* Ain't no subsequent arg */ + goto NO_ARG; + + sVal = argv[*pArgIdx+1]; + ++(*pArgIdx); + } + + strncpy(sDest, sVal, uDest - 1); + return true; + +NO_ARG: + das_error(DASERR_UTIL, "Missing option after argument %s", argv[*pArgIdx]); + return false; +} \ No newline at end of file diff --git a/das2/util.h b/das2/util.h index a7c67be..06f37dc 100644 --- a/das2/util.h +++ b/das2/util.h @@ -534,6 +534,62 @@ DAS_API int das_dirlist( */ DAS_API double das_strtod_c(const char *nptr, char **endptr); +/** See a given string matches the short or long form of an option + * + * This is commonly used in loops over each command line argument. It + * works for arguments in the form: + * + * -a value + * --my-arg=value + * + * The form that has spaces between the long option name and the value + * is not supported + * + * @param sArg - A string to test + * @param sShort - The short form of an option + * @param sLong - The long form of an option + * @param pLong - If not NULL, the associated bool value is set to true if + * the long form of a argument was found. + * + * @returns true if the string matches the given option, false otherwise + */ +bool dascmd_isArg(const char* sArg, const char* sShort, const char* sLong, bool* pLong); + + +/** Get the value of an argument if the current entry in argv matches + * either the short or long form of an option. + * + * This is typically used to test command line arguments in a loop. It + * works for arguments in the form: + * + * -a value + * --my-arg=value + * + * The form that has spaces between the long option name and the value + * is not supported + * + * @param sDest - The location to recieve the option value + * @param uDest - The size of the location to recive the option value + * Note the macro DAS_FIELD_SZ is useful for getting + * the size of a field in a structure. + * @param argv - The list of command line parameters + * @param argc - The number of command line parameters + * @param pArgIdx - A pointer to the current argument index. It is + * incremented if the option is found. + * @param sShort - The short form of the option + * @param sLong - The long form of the option + * + * @returns false if the argument was not found or the option value + * missing ofter the argument, true otherwise and the index at + * pArgInd is incremented. + * + * @see also DAS_FIELD_SZ + */ + bool dascmd_getArgVal( + char* sDest, size_t uDest, char** argv, int argc, int* pArgIdx, + const char* sShort, const char* sLong +); + /** @} */ diff --git a/utilities/das3_cdf.c b/utilities/das3_cdf.c index d6ee59b..ce49539 100644 --- a/utilities/das3_cdf.c +++ b/utilities/das3_cdf.c @@ -191,7 +191,7 @@ void prnHelp() " Directory for writing temporary files when run as a command\n" " pipeline filter. Defaults to \"%s\". Ignored if -o is given.\n" "\n" -" -c FILE,--credentials=FILE\n" +" -a FILE,--auth-toks=FILE\n" " Set the location where server authentication tokens (if any)\n" " are saved. Defaults to %s%s%s\n" "\n" @@ -237,6 +237,9 @@ void prnHelp() " -r,--remove Remove the destination file before writing. By default " PROG "\n" " refuses to overwrite an existing output file. Use with '-o'.\n" "\n" +" -c,--clean Automatically delete any CDFs output files that contain no\n" +" record varying data. Use with '-o'.\n" +"\n" " -u,-uncompressed\n" " Disable zlib compression. All variables are written uncompressed.\n" " This is needed for any CDF files submitted to the Planetary Data\n" @@ -289,59 +292,6 @@ HELP_TEMP_DIR, HOME_VAR_STR, DAS_DSEPS, DEF_AUTH_FILE); /* ************************************************************************* */ -/* See a given string matches the short or long form of an argument */ -static int _isArg( - const char* sArg, const char* sShort, const char* sLong, bool* pLong -){ - if(strcmp(sArg, sShort) == 0){ - if(pLong) *pLong = false; - return true; - } - size_t uLen = strlen(sLong); /* Include the '=' */ - - if(strncmp(sArg, sLong, uLen) == 0){ - if(pLong) *pLong = true; - return true; - } - return false; -} - -/* Get the value of an argument if the current entry in argv matches - * either the short or long form - */ -static bool _getArgVal( - char* sDest, size_t uDest, char** argv, int argc, int* pArgIdx, - const char* sShort, const char* sLong -){ - bool bIsLong = false; - - if(! _isArg(argv[*pArgIdx], sShort, sLong, &bIsLong)) - return false; - - const char* sVal; - if(bIsLong){ - size_t uLongSz = strlen(sLong); - if(argv[*pArgIdx][uLongSz] == '\0') /* Nothing in str after prefix */ - goto NO_ARG; - - sVal = argv[*pArgIdx] + uLongSz; - } - else{ - if(*pArgIdx > argc-2) /* Ain't no subsequent arg */ - goto NO_ARG; - - sVal = argv[*pArgIdx+1]; - ++(*pArgIdx); - } - - strncpy(sDest, sVal, uDest - 1); - return true; - -NO_ARG: - das_error(PERR, "Missing option after argument %s", argv[*pArgIdx]); - return false; -} - typedef struct program_options{ bool bRmFirst; /* remove output before writing */ bool bUncompressed; /* don't compress data */ @@ -357,8 +307,6 @@ typedef struct program_options{ char aCredFile[256]; } popts_t; -#define FIELD_SZ(type, field) (sizeof(((type*)NULL)->field)) - int parseArgs(int argc, char** argv, popts_t* pOpts) { memset(pOpts, 0, sizeof(popts_t)); /* <- Defaults struct values to 0 */ @@ -386,56 +334,56 @@ int parseArgs(int argc, char** argv, popts_t* pOpts) ++i; /* 1st time, skip past the program name */ if(argv[i][0] == '-'){ - if(_isArg(argv[i], "-h", "--help", NULL)){ + if(dascmd_isArg(argv[i], "-h", "--help", NULL)){ prnHelp(); exit(0); } - if(_isArg(argv[i], "-r", "--remove", NULL)){ + if(dascmd_isArg(argv[i], "-r", "--remove", NULL)){ pOpts->bRmFirst = true; continue; } - if(_isArg(argv[i], "-n", "--no-istp", NULL)){ + if(dascmd_isArg(argv[i], "-n", "--no-istp", NULL)){ pOpts->bNoIstp = true; continue; } - if(_isArg(argv[i], "-u", "--uncompressed", NULL)){ + if(dascmd_isArg(argv[i], "-u", "--uncompressed", NULL)){ pOpts->bUncompressed = true; continue; } - if(_isArg(argv[i], "-f", "--filter-vars", NULL)){ + if(dascmd_isArg(argv[i], "-f", "--filter-vars", NULL)){ pOpts->bFilterVars = true; continue; } - if(_getArgVal( + if(dascmd_getArgVal( sMemThresh, 32, argv, argc, &i, "-b", "--buffer=" )) continue; - if(_getArgVal( - pOpts->aTpltFile, FIELD_SZ(popts_t,aTpltFile), argv, argc, &i, "-s", "--skeleton=" + if(dascmd_getArgVal( + pOpts->aTpltFile, DAS_FIELD_SZ(popts_t,aTpltFile), argv, argc, &i, "-s", "--skeleton=" )) continue; - if(_getArgVal( - pOpts->aSource, FIELD_SZ(popts_t,aSource), argv, argc, &i, "-i", "--input=" + if(dascmd_getArgVal( + pOpts->aSource, DAS_FIELD_SZ(popts_t,aSource), argv, argc, &i, "-i", "--input=" )) continue; - if(_getArgVal( - pOpts->aOutFile, FIELD_SZ(popts_t,aOutFile), argv, argc, &i, "-o", "--output=" + if(dascmd_getArgVal( + pOpts->aOutFile, DAS_FIELD_SZ(popts_t,aOutFile), argv, argc, &i, "-o", "--output=" )) continue; - if(_getArgVal( - pOpts->aTmpDir, FIELD_SZ(popts_t,aTmpDir), argv, argc, &i, "-t", "--temp-dir=" + if(dascmd_getArgVal( + pOpts->aTmpDir, DAS_FIELD_SZ(popts_t,aTmpDir), argv, argc, &i, "-t", "--temp-dir=" )) continue; - if(_getArgVal( - pOpts->aMapFile, FIELD_SZ(popts_t,aMapFile), argv, argc, &i, "-m", "--map-vars=" + if(dascmd_getArgVal( + pOpts->aMapFile, DAS_FIELD_SZ(popts_t,aMapFile), argv, argc, &i, "-m", "--map-vars=" )) continue; - if(_getArgVal( - pOpts->aLevel, FIELD_SZ(popts_t,aLevel), argv, argc, &i, "-l", "--log=" + if(dascmd_getArgVal( + pOpts->aLevel, DAS_FIELD_SZ(popts_t,aLevel), argv, argc, &i, "-l", "--log=" )) continue; - if(_getArgVal( - pOpts->aCredFile, FIELD_SZ(popts_t,aCredFile), argv, argc, &i, "-c", "--credentials=" + if(dascmd_getArgVal( + pOpts->aCredFile, DAS_FIELD_SZ(popts_t,aCredFile), argv, argc, &i, "-a", "--auth-toks=" )) continue; return das_error(PERR, "Unknown command line argument %s", argv[i]); @@ -603,6 +551,7 @@ var_name_map_t* loadVarMap(const char* sFile) struct context { bool bCompress; bool bIstp; /* output some ITSP metadata (or don't) */ + uint64_t nRecsOut; /* Track how many record varying rows were written */ size_t uFlushSz; /* How big to let internal memory grow before a CDF flush */ CDFid nCdfId; char* sTpltFile; /* An empty template CDF to put data in */ @@ -2180,10 +2129,12 @@ const ubyte* _valueToTT2k( } } -DasErrCode _writeRecVaryAry(CDFid nCdfId, DasVar* pVar, DasAry* pAry) +DasErrCode _writeRecVaryAry(struct context* pCtx, DasVar* pVar, DasAry* pAry) { CDFstatus iStatus; /* Used by the CDF_MAD macro */ + CDFid nCdfId = pCtx->nCdfId; + /* It's possible that we didn't get any data, for example when a header is sent, but no actual values. If so just return okay. */ @@ -2242,6 +2193,8 @@ DasErrCode _writeRecVaryAry(CDFid nCdfId, DasVar* pVar, DasAry* pAry) DasVar_cdfIncStart(pVar, aShape[0]); + pCtx->nRecsOut += aShape[0]; + return DAS_OKAY; } @@ -2622,6 +2575,9 @@ int main(int argc, char** argv) if(ctx.nCdfId != 0) CDFclose(ctx.nCdfId); + daslog_info_v("") + if(opts.) + if(pInFile) fclose(pInFile); diff --git a/utilities/das3_rotate.c b/utilities/das3_rotate.c new file mode 100644 index 0000000..cca7a1c --- /dev/null +++ b/utilities/das3_rotate.c @@ -0,0 +1,281 @@ +/* Copyright (C) 2024 Chris Piker + * + * This file is part of das2C, the Core Das2 C Library. + * + * das2C is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License version 2.1 as published + * by the Free Software Foundation. + * + * das2C 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 Lesser General Public License for + * more details. + * + * You should have received a copy of the GNU Lesser General Public License + * version 2.1 along with das2C; if not, see . + */ + +/* ************************************************************************* + + das3_rotate: Change coordinate frames for vector variables + +**************************************************************************** */ + +#include + +#include + +#include +#include + +#define PROG "das3_rotate" +#define PERR 63 + +/* ************************************************************************* */ +/* Globals */ + +/* The maximum number of frame transforms handled by the program */ +#define MAX_XFORMS 24 + +/* Freak big stack variable to print frames. Hopefully C++ spice will allow + for heap data */ +#define MAX_DEFINED_FRAMES 100 + +/* ************************************************************************* */ +void prnHelp() +{ + printf( +"SYNOPSIS\n" +" " PROG " - Rotate vectors in das3 stream to new coordinate frames\n" +"\n" +"USAGE\n" +" " PROG " [options] META_KERNEL [IN_FRAME1:]OUT_FRAME1 [IN_FRAME1:OUT_FRAME2]\n" +"\n" +"DESCRIPTION\n" +" " PROG " is a filter, it reads das3 streams on standard input attempts to\n" +" and vector variables in the given INPUT_FRAME into the given OUTPUT_FRAME.\n" +" Rotation matricies are provide by the CSpice library driven by the given\n" +" META_KERNEL file. The transformed stream is written to standard output.\n" +" Since das2 streams do not have the concept of a geometric vector, das3\n" +" streams are expected as input.\n" +"\n" +" Transforms are specified by the set:\n" +"\n" +" INPUT_FRAME \":\" OUTPUT_FRAME\n" +"\n" +" without spaces! If the input frame is not given, all input vector frames\n" +" automatically match the transform rule. The program assumes that `:` is\n" +" not a legal character in a vector frame name." +"\n" +"OPTIONS\n" +" -h,--help Write this text to standard output and exit.\n" +"\n" +" -l LEVEL,--log=LEVEL\n" +" Set the logging level, where LEVEL is one of 'debug', 'info',\n" +" 'warning', 'error' in order of decreasing verbosity. All log\n" +" messages go to the standard error channel, the default is'info'.\n" +"\n" +" -a FRAME,--anonymous FRAME\n" +" If the input stream has anonymous vector frames, assume they are\n" +" in this frame.\n" +"\n" +" -c,--coords Only rotate matching coodinate vectors, ignore data vectors.\n" +"\n" +" -d,--data Only rotate data vectors, ignore matching coordinate vectors.\n" +"\n" +" -k,--keep By default original input vectors are not emitted on the output\n" +" stream, but the command line argument `-k` may be used to\n" +" preserve the original vectors alongside the rotated items.\n" +"\n" +" -L,--list An information option. Just print all frames defined in the\n" +" given metakernel to the standard error channel and exit\n" +"\n" +"EXAMPLES\n" +" 1. Just see what frames are defined in a given metakernel:\n" +"\n" +" das3_rotate -L my_metakernel.tm\n" +"\n" +" 2. Convert MAG data vectors from the any loaded coordiante system into the TSS\n" +" TSS frame and write the results to a CDF file:\n" +"\n" +" das_get site:uiowa/tracers/l1/mag/bdc_roi time:2024-01-01,2024-01-02 \\\n" +" | das3_rotate tra_metakern.tm TSS \\\n" +" | das3_cdf -o ./\\n" +"\n" +"AUTHOR\n" +" chris-piker@uiowa.edu\n" +"\n" +"SEE ALSO\n" +" * das_get, das3_cdf\n" +" * Wiki page https://github.com/das-developers/das2C/wiki/das3_rotate\n" +" * SPICE Frames https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/req/frames.html\n" +"\n"); + +} + +/* ************************************************************************* */ + +struct frame_xform { + const char* sOutFrame; /* May not be NULL */ + const char* sInFrame; /* May be NULL!, means try to match any */ +}; + +typedef struct program_options{ + bool bListFrames; + bool bCoordsOnly; + bool bDataOnly; + bool bKeepOrig; + char aLevel[32]; /* Log level */ + char aMetaKern[256]; /* The metakernel file name */ + char aAnonFrame[32]; + struct frame_xform aXForms[MAX_XFORMS + 1]; /* Always terminating null struct */ +} popts_t; + +int parseArgs(int argc, char** argv, popts_t* pOpts) +{ + memset(pOpts, 0, sizeof(popts_t)); /* <- Defaults struct values to 0 */ + + strncpy(pOpts->aLevel, "info", DAS_FIELD_SZ(popts_t,aLevel) - 1); + int iXForms = 0; + int i = 0; + while(i < (argc-1)){ + ++i; /* Increments an handily skips past the program name */ + + if(argv[i][0] == '-'){ + if(dascmd_isArg(argv[i], "-h", "--help", NULL)){ + prnHelp(); + exit(0); + } + if(dascmd_isArg(argv[i], "-c", "--coords", NULL)){ + pOpts->bCoordsOnly = true; + continue; + } + if(dascmd_isArg(argv[i], "-d", "--data", NULL)){ + pOpts->bDataOnly = true; + continue; + } + if(dascmd_isArg(argv[i], "-k", "--keep", NULL)){ + pOpts->bKeepOrig = true; + continue; + } + if(dascmd_isArg(argv[i], "-L", "--list", NULL)){ + pOpts->bListFrames = true; + continue; + } + if(dascmd_getArgVal( + pOpts->aLevel, DAS_FIELD_SZ(popts_t,aLevel), argv, argc, &i, + "-l", "--log=" + )) + continue; + if(dascmd_getArgVal( + pOpts->aAnonFrame, DAS_FIELD_SZ(popts_t,aAnonFrame), argv, argc, &i, + "-a", "--anonymous=" + )) + continue; + if(dascmd_getArgVal( + pOpts->aAnonFrame, DAS_FIELD_SZ(popts_t,aAnonFrame), argv, argc, &i, + "-a", "--anonymous=" + )) + continue; + + return das_error(PERR, "Unknown command line argument '%s'", argv[i]); + } + else{ + if(pOpts->aMetaKern[0] == '\0'){ + strncpy(pOpts->aMetaKern, argv[i], 255); + } + else{ + if(iXForms >= MAX_XFORMS){ + return das_error(PERR, + "Maximum number of frame transformations exceeded (%d)", MAX_XFORMS + ); + } + pOpts->aXForms[iXForms].sOutFrame = argv[i]; + + char* pSep = strchr(argv[i], ':'); + if(pSep != NULL){ + if(*(pSep+1) == '\0') + return das_error(PERR, "Output frame missing after ':' in '%s'", argv[i]); + + *pSep = '\0'; + pOpts->aXForms[iXForms].sInFrame = pSep + 1; + } + } + } + } /* end arg loop */ + + /* Check args */ + if(pOpts->aMetaKern[0] == '\0') + return das_error(PERR, "Meta-kernel file was not provided"); + + if(!(pOpts->bListFrames)){ + if(pOpts->aXForms[0].sOutFrame == NULL) + return das_error(PERR, "No frame transformations were given"); + } + + return DAS_OKAY; +} + +/* ************************************************************************* */ +/* Handy end-user tool, print frames defined in a kernel */ +void prnFrames(){ + + SpiceInt nFrmType[] = { + SPICE_FRMTYP_PCK, SPICE_FRMTYP_CK, SPICE_FRMTYP_TK, SPICE_FRMTYP_DYN, + SPICE_FRMTYP_SWTCH, 0 + }; + + const char* sFrmType[] = { + "PCK-based frames", "CK-based frames", "Text Kernel frames", + "Dynamic frames", "Switch frames", NULL + }; + + SPICEINT_CELL (cells, MAX_DEFINED_FRAMES); + + SpiceChar sFrame[ 34 ]; + + for(int i = 0; sFrmType[i] != NULL; ++i){ + + kplfrm_c(nFrmType[i], &cells); + fprintf(stderr, "There are %d %s frames defined:\n", (int)card_c(&cells), sFrmType[i]); + + for(int j = 0; j < card_c(&cells); ++j){ + SpiceInt nFrm = ((SpiceInt*)cells.data)[j]; + frmnam_c(nFrm, 33, sFrame); + fprintf(stderr, " %12d %s\n", nFrm, sFrame); + } + putc('\n', stderr); + } +} + +/* ************************************************************************* */ + +int main(int argc, char** argv) +{ + /* Exit on errors, log info messages and above */ + das_init(argv[0], DASERR_DIS_EXIT, 0, DASLOG_INFO, NULL); + + + popts_t opts; + + if(parseArgs(argc, argv, &opts) != DAS_OKAY) + return 13; + + daslog_setlevel(daslog_strlevel(opts.aLevel)); + + das_spice_err_setup(); /* Don't emit spice errors to stdout */ + + furnsh_c(opts.aMetaKern); + if(failed_c()){ + das_send_spice_err(3, DAS2_EXCEPT_SERVER_ERROR); + } + + /* Whole different path, just print stuff to stderr */ + if(opts.bListFrames){ + prnFrames(); + return 0; + } + + das_error(DASERR_NOTIMP, "Actual program body not yet impliment, just the -L option"); + return PERR; +}; \ No newline at end of file