From 8553bcfb32dea560e0e83cb318cfd150ad58cc69 Mon Sep 17 00:00:00 2001 From: Chris Piker Date: Fri, 28 Jun 2024 17:58:44 -0500 Subject: [PATCH] Initial CSV converter work --- buildfiles/Linux.mak | 2 +- das2/frame.c | 41 ++++-- das2/frame.h | 5 + das2/property.c | 4 +- das2/property.h | 3 + das2/serial.c | 29 ++++- das2/variable.h | 3 +- utilities/das2_csv.c | 227 --------------------------------- utilities/das3_cdf.c | 2 +- utilities/das3_csv.c | 293 +++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 363 insertions(+), 246 deletions(-) delete mode 100644 utilities/das2_csv.c create mode 100644 utilities/das3_csv.c diff --git a/buildfiles/Linux.mak b/buildfiles/Linux.mak index a1dce2c..cf8eaf4 100644 --- a/buildfiles/Linux.mak +++ b/buildfiles/Linux.mak @@ -29,7 +29,7 @@ endif UTIL_PROGS=das1_inctime das2_prtime das1_fxtime das2_ascii das2_bin_avg \ das2_bin_avgsec das2_bin_peakavgsec das2_from_das1 das2_from_tagged_das1 \ das1_ascii das1_bin_avg das2_bin_ratesec das2_psd das2_hapi das2_histo \ - das2_cache_rdr das3_node + das2_cache_rdr das3_node das3_csv TEST_PROGS:=TestUnits TestArray TestVariable LoadStream TestBuilder \ TestAuth TestCatalog TestTT2000 ex_das_cli ex_das_ephem TestCredMngr \ diff --git a/das2/frame.c b/das2/frame.c index 2b3bd05..42571ed 100644 --- a/das2/frame.c +++ b/das2/frame.c @@ -25,8 +25,38 @@ #include #endif +#include "log.h" #include "frame.h" + +const char* das_frametype2str( ubyte uFT) +{ + ubyte ft = uFT & DASFRM_TYPE_MASK; + + if(ft == DASFRM_CARTESIAN ) return "cartesian"; + if(ft == DASFRM_POLAR ) return "polar"; + if(ft == DASFRM_SPHERE_SURFACE) return "sphere_surface"; + if(ft == DASFRM_CYLINDRICAL ) return "cylindrical"; + if(ft == DASFRM_CYLINDRICAL ) return "spherical"; + + daslog_error_v("Unknown vector or coordinate frame type id: '%hhu'.", uFT); + return ""; +} + +ubyte das_str2frametype(const char* sFT) +{ + if( strcasecmp(sFT, "cartesian") == 0) return DASFRM_CARTESIAN; + if( strcasecmp(sFT, "polar") == 0) return DASFRM_POLAR; + if( strcasecmp(sFT, "sphere_surface") == 0) return DASFRM_SPHERE_SURFACE; + if( strcasecmp(sFT, "cylindrical") == 0) return DASFRM_CYLINDRICAL; + if( strcasecmp(sFT, "spherical") == 0) return DASFRM_CYLINDRICAL; + + daslog_error_v("Unknown vector or coordinate frame type: '%s'.", sFT); + return 0; +} + +/* ************************************************************************ */ + DasFrame* new_DasFrame(DasDesc* pParent, ubyte id, const char* sName, const char* sType) { DasFrame* pThis = (DasFrame*) calloc(1, sizeof(DasFrame)); @@ -154,16 +184,7 @@ DAS_API DasErrCode DasFrame_setType(DasFrame* pThis, const char* sType) return das_error(DASERR_FRM, "Empty coordinate frame type"); strncpy(pThis->type, sType, DASFRM_TYPE_SZ-1); - if( strcasecmp(pThis->type, "cartesian") == 0) - pThis->flags |= DASFRM_CARTESIAN; - else if( strcasecmp(pThis->type, "polar") == 0) - pThis->flags |= DASFRM_POLAR; - else if( strcasecmp(pThis->type, "sphere_surface") == 0) - pThis->flags |= DASFRM_SPHERE_SURFACE; - else if( strcasecmp(pThis->type, "cylindrical") == 0) - pThis->flags |= DASFRM_CYLINDRICAL; - else if( strcasecmp(pThis->type, "spherical") == 0) - pThis->flags |= DASFRM_CYLINDRICAL; + pThis->flags |= das_str2frametype(pThis->type); return DAS_OKAY; } diff --git a/das2/frame.h b/das2/frame.h index 80c0dfd..9ef3060 100644 --- a/das2/frame.h +++ b/das2/frame.h @@ -43,6 +43,11 @@ extern "C" { #define DASFRM_NULLNAME "_UNDEFINED_SOURCE_FRAME_" +/* Converting vecClass strings back and forth to frame type bytes */ +const char* das_frametype2str( ubyte uFT); + +ubyte das_str2frametype(const char* sFT); + /** @addtogroup DM * @{ */ diff --git a/das2/property.c b/das2/property.c index 46e7448..837482b 100644 --- a/das2/property.c +++ b/das2/property.c @@ -200,7 +200,7 @@ DasErrCode DasProp_init( uFlags |= (DASPROP_STRING | DASPROP_SINGLE); else if(strcasecmp(sType, "stringarray") == 0) uFlags |= (DASPROP_STRING | DASPROP_SET); - else if(strcasecmp(sType, "boolean") == 0) + else if((strcasecmp(sType, "boolean") == 0)||(strcasecmp(sType, "bool") == 0)) uFlags |= (DASPROP_BOOL | DASPROP_SINGLE); else if((strcasecmp(sType, "int") == 0)||(strcasecmp(sType, "integer") == 0)) uFlags |= (DASPROP_INT | DASPROP_SINGLE); @@ -227,7 +227,7 @@ DasErrCode DasProp_init( } else return das_error(DASERR_PROP, - "Invalid property type '%s' for value '%s'", sName, sValue + "Invalid property type '%s' for value '%s'", sType, sName ); /* If a range property was indicated, make sure there is a second value */ diff --git a/das2/property.h b/das2/property.h index 01a3b4b..194c899 100644 --- a/das2/property.h +++ b/das2/property.h @@ -116,6 +116,9 @@ DasErrCode DasProp_init( */ size_t DasProp_size(const DasProp* pProp); +/** Get the units for a property */ +#define DasProp_units(P) ((P)->units) + /** Get name of a property * @memberof DasProp */ diff --git a/das2/serial.c b/das2/serial.c index 9ea78ff..502f6c3 100644 --- a/das2/serial.c +++ b/das2/serial.c @@ -126,6 +126,7 @@ static void _serial_clear_var_section(context_t* pCtx) memset(pCtx->varUse, 0, DAS_FIELD_SZ(context_t, varUse) ); memset(pCtx->valSemantic, 0, DAS_FIELD_SZ(context_t, valSemantic) ); memset(pCtx->valStorage, 0, DAS_FIELD_SZ(context_t, valStorage) ); + memset(pCtx->varFrameType, 0, DAS_FIELD_SZ(context_t, varFrameType) ); memset(pCtx->varCompDirs, 0, DAS_FIELD_SZ(context_t, varCompDirs) ); memset(pCtx->varCompLbl, 0, DAS_FIELD_SZ(context_t, varCompLbl) ); /* HACK ALERT */ for(int i = 0; i < DASIDX_MAX; ++i) pCtx->aVarMap[i] = DASIDX_UNUSED; @@ -445,7 +446,10 @@ static void _serial_onOpenVar( strncpy(sIndex, psAttr[i+1], 31); else if(strcmp(psAttr[i], "units") == 0) pCtx->varUnits = Units_fromStr(psAttr[i+1]); - /* else if(strcmp(psAttr[i], )) */ + else if(strcmp(psAttr[i], "vecClass")){ + strncpy(pCtx->varFrameType, psAttr[i+1], DASFRM_TYPE_SZ-1); + pCtx->varFrameType[DASFRM_TYPE_SZ-1] = '\0'; + } /* Temporarily ignore values that are running around in wild */ else @@ -1212,6 +1216,9 @@ static void _serial_onCloseVar(context_t* pCtx) DasVar* pVar = NULL; DasErrCode nRet = DAS_OKAY; + /* May not matter if variable is a scalar */ + const char* sVecClass = pCtx->varFrameType[0] == '\0' ? "cartesian" : pCtx->varFrameType; + if(pCtx->varIntRank == 1){ /* HACK ALERT: Pick up names put in the wrong place and put them in a property instead */ @@ -1238,14 +1245,27 @@ static void _serial_onCloseVar(context_t* pCtx) const DasFrame* pFrame = DasStream_getFrameByName(pCtx->pSd, DasDim_getFrame(pCtx->pCurDim)); if(pFrame == NULL){ - /* If the stream had no frame, generate one for the given frame name */ + /* If the stream had no frame, generate one for the given frame name. + + BIG WARNING: + You want to use explicit frames in your streams... you really do. + + That is because MAGnetometer people often provide *cartesian* + vectors whose orthogonal unit vectors are set by the instantaneous + location in a *non-cartesian* coordinate frame! + + In order to properly take the magnitude of a vector you have to know + it's vector class and this may be different from the vector frame. + I know... wierd, right. + */ int iFrame = DasStream_newFrameId(pCtx->pSd); if(iFrame < 0){ pCtx->nDasErr = -1*iFrame; goto NO_CUR_VAR; } + DasFrame* pMkFrame = DasStream_createFrame( - pCtx->pSd, iFrame, DasDim_getFrame(pCtx->pCurDim), "cartesian" + pCtx->pSd, iFrame, DasDim_getFrame(pCtx->pCurDim), sVecClass ); DasDesc_setStr((DasDesc*)pMkFrame, "title", "Autogenerated Frame"); @@ -1286,9 +1306,10 @@ static void _serial_onCloseVar(context_t* pCtx) goto NO_CUR_VAR; } + // Use the given vector class here, even if frame is a different class pVar = new_DasVarVecAry( pCtx->pCurAry, DasDs_rank(pCtx->pDs), pCtx->aVarMap, 1, /* internal rank = 1 */ - pFrame->name, iFrame, pFrame->flags, pCtx->nVarComp, aDirs + pFrame->name, iFrame, das_str2frametype(sVecClass), pCtx->nVarComp, aDirs ); } else{ diff --git a/das2/variable.h b/das2/variable.h index f8e69d2..2ce05fd 100644 --- a/das2/variable.h +++ b/das2/variable.h @@ -575,7 +575,8 @@ DAS_API DasVar* new_DasVarArray(DasAry* pAry, int nExtRank, int8_t* pMap, int nI * @param nFrameId The integer id of this frame. GeoVec datums only store * the frame ID, not the name for faster comparisons * - * @param frametype The lower byte of DasFrame.flags + * @param frametype One of: DASFRM_CARTESIAN, DASFRM_POLAR, DASFRM_SPHERE_SURFACE + * DASFRM_CYLINDRICAL, or DASFRM_SPHERICAL * * @param pDir A mapping between coordinate directions and the components * of each vector, may be NULL. diff --git a/utilities/das2_csv.c b/utilities/das2_csv.c deleted file mode 100644 index 16b4ef3..0000000 --- a/utilities/das2_csv.c +++ /dev/null @@ -1,227 +0,0 @@ -/* Copyright (C) 2020 Chris Piker - * - * This file is part of libdas2, the Core Das2 C Library. - * - * Libdas2 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. - * - * Libdas2 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 libdas2; if not, see . - */ - -#define _POSIX_C_SOURCE 200112L - -#include -#include -#include -#include -#include -#include - -#ifndef _WIN32 -#include -#endif - -#include - -/* State ******************************************************************** */ - -int g_nTimeWidth = 24; /* default to 'time24' */ -const char* g_sTimeFmt = NULL; - -int g_n8ByteWidth = 17; /* default to 'ascii17' for 8-byte floats */ -int g_n4ByteWidth = 14; /* default to 'ascii14' for 4-byte floats */ -char g_sSep[12] = {';', '\0'}; - -/* Help ********************************************************************* */ - -void prnHelp(FILE* pOut) -{ - fprintf(pOut, -"SYNOPSIS:\n" -" das2_csv - Export a das2 stream to a delimited text format\n" -"\n" -"USAGE:\n" -" das2_csv [-r DIGITS] [-s SUBSEC] [-d DELIM]\n" -"\n" -"DESCRIPTION\n" -" das2_csv is a filter. It reads a das2 stream on standard input and writes\n" -" a text delimited stream suitable for use in comman spreadsheet programs to\n" -" standard output.\n" -"\n" -" Each das2 packet header encountered in the das2 stream is collapsed to a\n" -" single text header row. Since the stream may contain any number of packet\n" -" headers, the output may contain any number of header rows. Users of the\n" -" output CSV data should be on the look out for this condition if it would\n" -" adversely impact thier downstream software.\n" -"\n" -" By default the field delimiter character is a ';' (semicolon).\n" -"\n" -" By default 32-bit floating points numbers are written with 7 significant\n" -" digits in the mantissa and 2 digits in the exponent. Any 64-bit floats\n" -" encontered in the input stream are written with 17 significant digits in\n" -" the mantissa and 2 digits in the exponent. Binary time values are written\n" -" as ISO-8601 timestamps with microsecond resolution, i.e. the pattern\n" -" yyyy-mm-ddThh:mm:ss.ssssss\n" -"\n" -" All output values are rounded normally instead of truncating fractions.\n" -"\n" -" All output text is encoded as UTF-8.\n" -"\n" -"OPTIONS:\n" -"\n" -" -h,--help\n" -" Print this help text\n" -"\n" -" -d DELIM Change the default text delimiter from ';' (semicolon) to some\n" -" other UTF-8 character.\n" -"\n" -" -r DIGITS Set the number of significant digits for general output. The\n" -" minimum resolution is 2 significant digits.\n" -"\n" -" -s SUBSEC Set the sub-second resolution. Output N digits of sub-second\n" -" resolution. The minimum value is 0, thus time values are\n" -" are always output to at least seconds resolution.\n" -"\n" -"AUTHORS:\n" -" chris-piker@uiowa.edu\n" -"\n" -"SEE ALSO:\n" -" das2_ascii, das2_binary, das2_hapi\n" -"\n" -" and the das 2 ICD @ http://das2.org for an introduction to the das 2 system.\n" -"\n"); -} - -/* Headers ****************************************************************** */ - -DasErrCode OnPktHdr(StreamDesc* pSdIn, PktDesc* pPdIn, void* vpSep) -{ - PlaneDesc* pPlOut = NULL; - - /* For each plane, print a header */ - for(size_t u = 0; u < PktDesc_getNPlanes(pPdIn); u++){ - pPlOut = PktDesc_getPlane(pPdOut, u); - } -} - -/* Data ********************************************************************* */ - -DasErrCode onPktData(PktDesc* pPdIn, void* vpSep) -{ - -} - - -/* Exceptions *************************************************************** */ - -DasErrCode onException(OobExcept* pExcept, void* vpSep) -{ - /* Can't do much here but quit with log message */ - fprintf(stderr, "Stream Exception: %s, %s\n", pExcept->sType, pExcept->sMsg); - - return DAS_OKAY; -} - -/* Main ********************************************************************* */ - -int main( int argc, char *argv[]) { - - int i = 0; - int status = 0; - int nGenRes = 7; - int nSecRes = 3; - char sTimeFmt[64] = {'\0'}; - - /* Exit on errors, log info messages and above */ - das_init(argv[0], DASERR_DIS_EXIT, 0, DASLOG_INFO, NULL); - - for(i = 1; i < argc; i++){ - if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0 ){ - prnHelp(); - return 0; - } - - if(strcmp(argv[i], "-r") == 0){ - i++; - if(i >= argc){ - fprintf(stderr, "ERROR: Resolution parameter missing after -r\n"); - return 13; - } - nGenRes = atoi(argv[i]); - if(nGenRes < 2 || nGenRes > 18){ - fprintf(stderr, "ERROR: Can't format to %d significant digits, " - "Supported range is only 2 to 18 significant digits.\n", - nGenRes); - return 13; - } - continue; - } - - if(strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--version") == 0){ - printf("$TODO: Find a git auto substitution method$\n"); - return 0; - } - - if(strcmp(argv[i], "-s") == 0){ - i++; - if(i >= argc){ - fprintf(stderr, "ERROR: Sub-seconds resolution parameter missing after -s\n"); - return 13; - } - nSecRes = atoi(argv[i]); - if(nSecRes < 0 || nSecRes > 9){ - fprintf(stderr, "ERROR: Only 0 to 9 sub-seconds digits supported " - "don't know how to handle %d sub-second digits.", nSecRes); - return 13; - } - continue; - } - - if(strcmp(argv[i], "-d") == 0){ - for(int j = 0; (j < strlen(argv[i])) && (j < 11); ++j) - sSep[j] = argv[i][j]; - continue; - } - - fprintf(stderr, "ERROR: unknown parameter '%s'\n", argv[i]); - return 13; - } - - if(nGenRes != 7){ - g_n4ByteWidth = nGenRes + 7; - g_n8ByteWidth = nGenRes + 7; - } - - if(nSecRes != 3){ - if(nSecRes == 0) - g_nTimeWidth = 20; - else - g_nTimeWidth = 21 + nSecRes; - - sprintf(sTimeFmt, "%%04d-%%02d-%%02dT%%02d:%%02d:%%0%d.%df", - nSecRes + 3, nSecRes); - g_sTimeFmt = sTimeFmt; - } - - StreamHandler* pSh = new_StreamHandler(NULL); - - pSh->streamDescHandler = NULL; - pSh->pktDescHandler = OnPktHdr; - pSh->pktDataHandler = onPktData; - pSh->exceptionHandler = onException; - pSh->commentHandler = NULL; - pSh->closeHandler = onClose; - - DasIO* pIn = new_DasIO_cfile("Standard Input", stdin, "r"); - DasIO_addProcessor(pIn, pSh); - - int nRet = DasIO_readAll(pIn); - return nRet; -} diff --git a/utilities/das3_cdf.c b/utilities/das3_cdf.c index 4ea5e94..03fc2e5 100644 --- a/utilities/das3_cdf.c +++ b/utilities/das3_cdf.c @@ -200,7 +200,7 @@ void prnHelp() " -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" +" messages go to the standard error channel, the default is 'info'.\n" "\n" " -c FILE,--credentials=FILE\n" " Set the location where server authentication tokens (if any)\n" diff --git a/utilities/das3_csv.c b/utilities/das3_csv.c new file mode 100644 index 0000000..3623c6f --- /dev/null +++ b/utilities/das3_csv.c @@ -0,0 +1,293 @@ +/* Copyright (C) 2024 Chris Piker + * + * This file is part of das2C, the Core DAS 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 . + */ + +#define _POSIX_C_SOURCE 200112L + +#include +#include +#include +#include +#include +#include + +#ifndef _WIN32 +#include +#endif + +#include + +/* State ******************************************************************** */ + +int g_nTimeWidth = 24; /* default to 'time24' */ +const char* g_sTimeFmt = NULL; + +int g_n8ByteWidth = 17; /* default to 'ascii17' for 8-byte floats */ +int g_n4ByteWidth = 14; /* default to 'ascii14' for 4-byte floats */ +char g_sSep[12] = {';', '\0'}; + +bool g_bPropOut = false; + +#define PERR (DASERR_MAX + 1) + +/* Help ********************************************************************* */ + +void prnHelp() +{ + printf( +"SYNOPSIS:\n" +" das3_csv - Export das streams to a delimited text format\n" +"\n" +"USAGE:\n" +" das3_csv [-p] [-r DIGITS] [-s SUBSEC] [-d DELIM] < INFILE\n" +"\n" +"DESCRIPTION\n" +" das3_csv is a filter. It reads a das2 or das3 stream on standard input and\n" +" writes a delimited text stream suitable for use in comman spreadsheet\n" +" handler to standard output.\n" +"\n" +" Each dataset encountered in the input stream is collapsed to a single text\n" +" header row for rank-1 data and two header rows for rank 2 or greater. Since\n" +" the stream may contain any number of datasets, the output may contain any\n" +" number of header rows. Users of the output should be on the look out for\n" +" this condition if it would adversely adversely impact thier downstream\n" +" software.\n" +"\n" +" Each output row will contain the minimum number of field separators needed\n" +" to distinguish the fields in that particular row. No attempt is made to\n" +" output the same number of field separators for all rows. Thus das3_csv is\n" +" *not* strictly RFC-4180 compliant.\n" +"\n" +"DEFAULTS:\n" +" * All object properties are dropped, except those used in header rows.\n" +"\n" +" * The field delimiter character is a ';' (semicolon).\n" +"\n" +" * Input UTF-8 values are output as-is, without conversions\n" +"\n" +" * 32-bit floating point values are written with 6 significant digits in\n" +" the mantissa and 2 digits in the exponent.\n" +"\n" +" * 64-bit floating point values are written with 16 significant digits in\n" +" the mantissa and 2 digits in the exponent.\n" +"\n" +" * Time values are written as ISO-8601 timestamps with microsecond resolution,\n" +" i.e. the pattern YYYY-MM-DDTHH:mm:SS.ssssss\n" +"\n" +" * All output values are rounded normally instead of truncating fractions.\n" +"\n" +" * All output text is encoded as UTF-8.\n" +"\n" +"OPTIONS:\n" +"\n" +" -h,--help Show this help text\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" +" -p,--props Output object property rows. Each property row is tagged with\n" +" a 1st column containing the string '#property#'\n" +"\n" +" -d DELIM Change the default text delimiter from ';' (semicolon) to some\n" +" other ASCII 7-bit character.\n" +"\n" +" -r DIGITS Set the number of significant digits for general output. The\n" +" minimum resolution is 2 significant digits.\n" +"\n" +" -s SUBSEC Set the sub-second resolution. Output N digits of sub-second\n" +" resolution. The minimum value is 0, thus time values are\n" +" are always output to at least seconds resolution.\n" +"\n" +"AUTHOR:\n" +" chris-piker@uiowa.edu\n" +"\n" +"SEE ALSO:\n" +" das2_ascii, das3_cdf\n" +); +} + +/* Stream Start ************************************************************* */ + +DasErrCode onStream(StreamDesc* pSd, void* pUser) +{ + if(!g_bPropOut) return DAS_OKAY; + + size_t uProps = DasDesc_length((DasDesc*)pSd); + for(size_t u = 0; u < uProps; ++u){ + const DasProp* pProp = DasDesc_getPropByIdx((DasDesc*)pSd, u); + if(pProp == NULL) continue; + + // Write in the order: sope name, type, units, value + // for multi-value properties, use the spreadsheet's separator, not whatever + // the property may have been using + + printf("\"#property\",\"%s\",\"%s\",\"%s\"", DasProp_name(pProp), + DasProp_typeStr3(pProp), DasProp_units(pProp) + ); + + const char* sVal = DasProp_value(pProp); + if(DasProp_items(pProp) < 2){ + printf("%s\r\n", sVal); + } + else{ + char cSep = DasProp_sep(pProp); + putchar('"'); + while(*sVal != '\0'){ + if(*sVal == cSep) + printf("\"%s\"", g_sSep); + else + putchar(*sVal); + } + puts("\"\r\n"); + } + } + return DAS_OKAY; +} + + +/* DataSet Start ************************************************************* */ + +DasErrCode onDataSet(StreamDesc* pSd, int iPktId, DasDs* pDs, void* pUser) +{ + return DAS_OKAY; +} + +/* Dataset update ************************************************************ */ + +DasErrCode onData(StreamDesc* pSd, int iPktId, DasDs* pDs, void* pUser) +{ + return DAS_OKAY; +} + +/* Exceptions *************************************************************** */ + +DasErrCode onExcept(OobExcept* pExcept, void* vpSep) +{ + /* Can't do much here but quit with log message */ + fprintf(stderr, "Stream Exception: %s, %s\n", pExcept->sType, pExcept->sMsg); + + return DAS_OKAY; +} + +/* ************************************************************************* */ +DasErrCode onClose(StreamDesc* pSd, void* pUser) +{ + + return DAS_OKAY; +} + +/* Main ********************************************************************* */ + +int main( int argc, char *argv[]) { + + int i = 0; + /* int status = 0; */ + int nGenRes = 7; + int nSecRes = 3; + char sTimeFmt[64] = {'\0'}; + const char* sLevel = "info"; + + /* Exit on errors, log info messages and above */ + das_init(argv[0], DASERR_DIS_EXIT, 0, DASLOG_INFO, NULL); + + for(i = 1; i < argc; i++){ + if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0 ){ + prnHelp(); + return 0; + } + + if(strcmp(argv[i], "-r") == 0){ + i++; + if(i >= argc) + return das_error(PERR, "Resolution parameter missing after -r\n"); + + nGenRes = atoi(argv[i]); + if(nGenRes < 2 || nGenRes > 18) + return das_error(PERR, + "Can't format to %d significant digits, supported range is " + "only 2 to 18 significant digits.\n", nGenRes + ); + + continue; + } + if(strcmp(argv[i], "-l") == 0 || strcmp(argv[i], "--log") == 0){ + sLevel = argv[i]; + continue; + } + + if(strcmp(argv[i], "-s") == 0){ + i++; + if(i >= argc) + return das_error(PERR,"Sub-seconds resolution parameter missing after -s\n"); + + nSecRes = atoi(argv[i]); + if(nSecRes < 0 || nSecRes > 9) + return das_error( + PERR, "Only 0 to 9 sub-seconds digits supported don't know how to " + "handle %d sub-second digits.", nSecRes + ); + continue; + } + + if(strcmp(argv[i], "-d") == 0){ + int j; + for(j = 0; (j < strlen(argv[i])) && (j < 11); ++j){ + g_sSep[j] = argv[i][j]; + } + g_sSep[j] = '\0'; + continue; + } + + return das_error(PERR, "unknown parameter '%s'\n", argv[i]); + } + + daslog_setlevel(daslog_strlevel(sLevel)); + + if(nGenRes != 7){ + g_n4ByteWidth = nGenRes + 7; + g_n8ByteWidth = nGenRes + 7; + } + + if(nSecRes != 3){ + if(nSecRes == 0) + g_nTimeWidth = 20; + else + g_nTimeWidth = 21 + nSecRes; + + sprintf(sTimeFmt, "%%04d-%%02d-%%02dT%%02d:%%02d:%%0%d.%df", + nSecRes + 3, nSecRes); + g_sTimeFmt = sTimeFmt; + } + + StreamHandler handler; + memset(&handler, 0, sizeof(StreamHandler)); + handler.streamDescHandler = onStream; + handler.dsDescHandler = onDataSet; + handler.dsDataHandler = onData; + handler.exceptionHandler = onExcept; + handler.closeHandler = onClose; + /* handler.userData = &ctx; */ + + DasIO* pIn = new_DasIO_cfile("Standard Input", stdin, "r"); + DasIO_model(pIn, 3); /* Upgrade any das2 s to das3 s */ + + DasIO_addProcessor(pIn, &handler); + + int nRet = DasIO_readAll(pIn); + return nRet; +}