diff --git a/app/cmScore.c b/app/cmScore.c index b531a30..8637a24 100644 --- a/app/cmScore.c +++ b/app/cmScore.c @@ -6,6 +6,7 @@ #include "cmCtx.h" #include "cmMem.h" #include "cmMallocDebug.h" +#include "cmLinkedHeap.h" #include "cmMidi.h" #include "cmLex.h" #include "cmCsv.h" @@ -13,6 +14,7 @@ #include "cmMidiFile.h" #include "cmAudioFile.h" #include "cmTimeLine.h" +#include "cmText.h" #include "cmScore.h" #include "cmVectOpsTemplateMain.h" @@ -41,7 +43,8 @@ enum kFracColScIdx = 18, kDynColScIdx = 19, kSectionColScIdx = 20, - kRemarkColScIdx = 21 + kRecdPlayColScIdx = 21, + kRemarkColScIdx = 22 }; @@ -75,6 +78,15 @@ typedef struct cmScSet_str struct cmScSet_str* link; // } cmScSet_t; +typedef struct cmScMark_str +{ + cmMarkScMId_t cmdId; + unsigned labelSymId; + unsigned scoreIdx; + unsigned csvRowIdx; + struct cmScMark_str* link; +} cmScMark_t; + typedef struct { cmErr_t err; @@ -94,11 +106,15 @@ typedef struct cmScoreSection_t* sect; unsigned sectCnt; + unsigned* markLabelArray; // one symId per unique cmScoreMarker_t.labelSymId; + unsigned markLabelCnt; + unsigned sciPitchLexTId; // sci pitch and section id lexer token id's unsigned sectionLexTId; cmScSect_t* sectList; // lists used during parsing cmScSet_t* setList; + cmScMark_t* markList; cmScoreSet_t* sets; unsigned setCnt; @@ -313,6 +329,17 @@ unsigned _cmScLexSectionIdMatcher( const cmChar_t* cp, unsigned cn ) return 0; } +void _cmScFreeMarkList( cmScMark_t* markList ) +{ + cmScMark_t* mp = markList; + while( mp!=NULL ) + { + cmScMark_t* np = mp->link; + cmMemFree(mp); + mp = np; + } +} + void _cmScFreeSetList( cmScSet_t* setList ) { cmScSet_t* tp = setList; @@ -366,6 +393,8 @@ cmScRC_t _cmScFinalize( cmSc_t* p ) _cmScFreeSetList(p->setList); + _cmScFreeMarkList(p->markList); + if( p->loc != NULL ) { for(i=0; ilocCnt; ++i) @@ -373,12 +402,23 @@ cmScRC_t _cmScFinalize( cmSc_t* p ) cmMemFree(p->loc[i].evtArray); if( p->loc[i].begSectPtr != NULL ) cmMemFree(p->loc[i].begSectPtr->setArray); + + // free the marker list assoc'd with this location + cmScoreMarker_t* smp = p->loc[i].markList; + while( smp!=NULL ) + { + cmScoreMarker_t* np = smp->link; + cmMemFree(smp); + smp = np; + } + } cmMemFree(p->loc); } + cmMemPtrFree(&p->dynRefArray); - + cmMemFree(p->markLabelArray); cmMemFree(p->sect); cmMemFree(p->fn); cmMemFree(p->array); @@ -557,6 +597,79 @@ cmScRC_t _cmScParseAttr(cmSc_t* p, unsigned scoreIdx, const cmChar_t* text, unsi return kOkScRC; } +// Parse a record/playback string +cmScRC_t _cmScParseMarkers( cmSc_t* p, unsigned scoreIdx, const cmChar_t* text, unsigned rowIdx ) +{ + const cmChar_t* cp = text; + const cmChar_t* ip; + const cmChar_t* ep; + + // if no symbol table has been registered then don't bother storing markers. + // (NOTE - THIS IS A HACK BECAUSE THE SCORE OBJECT USED IN THE cmdIf DOES NOT HAVE + // A SYMBOL TABLE - WE COULD EASILY ADD ONE IF IT EVENTUALLY NEEDS ACCESS TO THE MARKERS + // - OR A SYMBOL TABLE COULD BE ADDED TO THE SCORE ITSELF.) + if( cmSymTblIsValid(p->stH) == false ) + return kOkScRC; + + // go to command/id space + if((ip = cmTextNextWhiteOrEosC(text)) == NULL ) + goto errLabel; + + // goto label + if((ip = cmTextNextNonWhiteC(ip)) == NULL ) + goto errLabel; + + // goto end of label + if((ep = cmTextNextWhiteOrEosC(ip)) == NULL ) + goto errLabel; + else + { + unsigned n = (ep-ip)+1; + cmChar_t markTextStr[n+1]; + strncpy(markTextStr,ip,n); + + // for each command code + // (there may be more than one character) + for(; *cp && !isspace(*cp); ++cp) + { + cmMarkScMId_t cmdId = kInvalidScMId; + + switch( *cp ) + { + case 'c': cmdId = kRecdBegScMId; break; + case 'e': cmdId = kRecdEndScMId; break; + case 'p': cmdId = kPlayBegScMId; break; + case 'd': cmdId = kPlayEndScMId; break; + case 'f': cmdId = kFadeScMId; break; + default: + return cmErrMsg(&p->err,kSyntaxErrScRC,"Unrecognized marker command character '%c' at row index %i.",*cp,rowIdx); + } + + cmScMark_t* mp = cmMemAllocZ(cmScMark_t,1); + mp->cmdId = cmdId; + mp->labelSymId = cmSymTblRegisterSymbol(p->stH,markTextStr); + mp->scoreIdx = scoreIdx; + mp->csvRowIdx = rowIdx; + + // insert the new mark at the end of the list + if( p->markList == NULL ) + p->markList = mp; + else + { + cmScMark_t* ep = p->markList; + while( ep->link != NULL ) + ep = ep->link; + + ep->link = mp; + } + } + } + return kOkScRC; + + errLabel: + return cmErrMsg(&p->err,kSyntaxErrScRC,"Invalid record/playback field ('%s') on row index:%i.",cmStringNullGuard(text),rowIdx); +} + void _cmScPrintSets( const cmChar_t* label, cmScSet_t* setList ) { printf("%s\n",label); @@ -598,7 +711,7 @@ cmScRC_t _cmScParseNoteOn( cmSc_t* p, unsigned rowIdx, cmScoreEvt_t* s, unsigned return cmErrMsg(&p->err,kSyntaxErrScRC,"Expected a scientific pitch value"); if((midiPitch = cmSciPitchToMidi(sciPitch)) == kInvalidMidiPitch) - return cmErrMsg(&p->err,kSyntaxErrScRC,"Unable to convert the scientific pitch '%s' to a MIDI value. "); + return cmErrMsg(&p->err,kSyntaxErrScRC,"Unable to convert the scientific pitch '%s' to a MIDI value. "); // it is possible that note delta-secs field is empty - so default to 0 if((secs = cmCsvCellDouble(p->cH, rowIdx, kSecsColScIdx )) == DBL_MAX) // Returns DBL_MAX on error. @@ -658,6 +771,14 @@ cmScRC_t _cmScParseNoteOn( cmSc_t* p, unsigned rowIdx, cmScoreEvt_t* s, unsigned durSecs = 0.25; + // parse the recd/play markers + if((attr = cmCsvCellText(p->cH,rowIdx,kRecdPlayColScIdx)) != NULL ) + { + if((rc = _cmScParseMarkers(p,scoreIdx,attr,rowIdx)) != kOkScRC ) + return rc; + } + + s->type = kNonEvtScId; s->secs = secs; s->pitch = midiPitch; @@ -870,6 +991,8 @@ cmScRC_t _cmScProcSets( cmSc_t* p ) } + + cmScRC_t _cmScProcSections( cmSc_t* p, cmScSect_t* sectList ) { cmScRC_t rc = kOkScRC; @@ -935,6 +1058,153 @@ cmScRC_t _cmScProcSections( cmSc_t* p, cmScSect_t* sectList ) return rc; } +const cmScoreLoc_t* _cmScFindMarkLoc( cmSc_t* p, cmMarkScMId_t cmdId, unsigned labelSymId, const cmScoreMarker_t** markRef ) +{ + unsigned i; + for(i=0; ilocCnt; ++i) + { + cmScoreMarker_t* smp = p->loc[i].markList; + for(; smp!=NULL; smp=smp->link) + { + if( smp->markTypeId==cmdId && smp->labelSymId==labelSymId ) + return p->loc + i; + + if( markRef != NULL ) + *markRef = smp; + } + } + return NULL; +} + +unsigned _cmScMarkerLabelIndex( cmSc_t* p, unsigned labelSymId ) +{ + unsigned i; + for(i=0; imarkLabelCnt; ++i) + if( p->markLabelArray[i] == labelSymId ) + return i; + + return cmInvalidIdx; +} + + +// Verify that the record/play begin/end and fade markers fall in the correct time order. +// (e.g. 'begin' must be before 'end' and 'fade' must be between and 'begin' and 'end'). +cmScRC_t _cmScValidateMarkers( cmSc_t* p ) +{ + cmScRC_t rc = kOkScRC; + unsigned i; + + for(i=0; ilocCnt; ++i) + { + cmScoreMarker_t* sm0p = p->loc[i].markList; + for(; sm0p!=NULL; sm0p=sm0p->link) + { + const cmScoreLoc_t* sl0p; + const cmScoreLoc_t* sl1p; + + switch( sm0p->markTypeId ) + { + case kRecdBegScMId: + if((sl0p = _cmScFindMarkLoc(p,kRecdEndScMId, sm0p->labelSymId, NULL )) == NULL ) + rc = cmErrMsg(&p->err,kSyntaxErrScRC,"The 'record begin' marker at CSV row index %i does not have an associated 'record end' marker.",sm0p->csvRowIdx); + else + if( sl0p->index <= p->loc[i].index ) + rc = cmErrMsg(&p->err,kSyntaxErrScRC,"The 'record end' marker comes before associated with the 'record begin' marker at CSV row index %i.",sm0p->csvRowIdx); + break; + + case kRecdEndScMId: + if((sl0p = _cmScFindMarkLoc(p,kRecdBegScMId, sm0p->labelSymId, NULL )) == NULL ) + rc = cmErrMsg(&p->err,kSyntaxErrScRC,"The 'record end' marker at CSV row index %i does not have an associated 'record begin' marker.",sm0p->csvRowIdx); + else + if( sl0p->index > p->loc[i].index ) + rc = cmErrMsg(&p->err,kSyntaxErrScRC,"The 'record begin' marker comes after the associated with the 'record end' marker at CSV row index %i.",sm0p->csvRowIdx); + break; + + case kFadeScMId: + if((sl0p = _cmScFindMarkLoc(p,kRecdBegScMId, sm0p->labelSymId, NULL )) == NULL ) + rc = cmErrMsg(&p->err,kSyntaxErrScRC,"The 'fade' marker at CSV row index %i does not have an associated 'record begin' marker.",sm0p->csvRowIdx); + else + if((sl1p = _cmScFindMarkLoc(p,kRecdEndScMId, sm0p->labelSymId, NULL )) == NULL ) + rc = cmErrMsg(&p->err,kSyntaxErrScRC,"The 'fade' marker at CSV row index %i does not have an associated 'record end' marker.",sm0p->csvRowIdx); + else + if( sl0p->index > p->loc[i].index || sl1p->index < p->loc[i].index ) + rc = cmErrMsg(&p->err,kSyntaxErrScRC,"The 'fade' marker at CSV row index %i is not between it's associated 'record begin' and 'record end' markers.",sm0p->csvRowIdx); + break; + + case kPlayBegScMId: + if((sl0p = _cmScFindMarkLoc(p,kPlayEndScMId, sm0p->labelSymId, NULL )) == NULL ) + rc = cmErrMsg(&p->err,kSyntaxErrScRC,"The 'play begin' marker at CSV row index %i does not have an associated 'play end' marker.",sm0p->csvRowIdx); + else + if( sl0p->index <= p->loc[i].index ) + rc = cmErrMsg(&p->err,kSyntaxErrScRC,"The 'play end' marker comes before associated with the 'play begin' marker at CSV row index %i.",sm0p->csvRowIdx); + break; + + case kPlayEndScMId: + if((sl0p = _cmScFindMarkLoc(p,kPlayBegScMId, sm0p->labelSymId, NULL )) == NULL ) + rc = cmErrMsg(&p->err,kSyntaxErrScRC,"The 'play end' marker at CSV row index %i does not have an associated 'play begin' marker.",sm0p->csvRowIdx); + else + if( sl0p->index > p->loc[i].index ) + rc = cmErrMsg(&p->err,kSyntaxErrScRC,"The 'play begin' marker comes after the associated with the 'play end' marker at CSV row index %i.",sm0p->csvRowIdx); + break; + + default: + break; + + } + } + } + + return rc; +} + + + +cmScRC_t _cmScProcMarkers( cmSc_t* p ) +{ + // for each marker in the p->markList + // (p->markList is created by _cmScParseMarkers() during CSV file parsing.) + cmScMark_t* mp = p->markList; + for(; mp!=NULL; mp=mp->link) + { + assert( mp->scoreIdx < p->cnt ); + + // get the score location assoc'd with this marker + unsigned locIdx = p->array[ mp->scoreIdx ].locIdx; + assert( locIdx < p->locCnt ); + + cmScoreLoc_t* slp = p->loc + locIdx; + + // create a cmScoreMarker record. + cmScoreMarker_t* smp = cmMemAllocZ(cmScoreMarker_t,1); + smp->markTypeId = mp->cmdId; + smp->labelSymId = mp->labelSymId; + smp->csvRowIdx = mp->csvRowIdx; + smp->scoreLocPtr = slp; + + // attach the new scoreMarker record to the assoc'd score loc. recd + if( slp->markList == NULL ) + slp->markList = smp; + else + { + cmScoreMarker_t* sm0p = slp->markList; + while( sm0p->link != NULL ) + sm0p = sm0p->link; + sm0p->link = smp; + } + + // if the id represented by this marker + if( _cmScMarkerLabelIndex(p,smp->labelSymId) == cmInvalidIdx ) + { + p->markLabelArray = cmMemResizeP(unsigned,p->markLabelArray,p->markLabelCnt+1); + p->markLabelArray[p->markLabelCnt] = smp->labelSymId; + p->markLabelCnt += 1; + } + } + + // validate the markers + return _cmScValidateMarkers(p); +} + cmScRC_t _cmScParseFile( cmSc_t* p, cmCtx_t* ctx, const cmChar_t* fn ) { cmScRC_t rc = kOkScRC; @@ -1036,27 +1306,30 @@ cmScRC_t _cmScParseFile( cmSc_t* p, cmCtx_t* ctx, const cmChar_t* fn ) break; } - if( secs != DBL_MAX ) - cur_secs = secs; - - // form the section list - if( j > 0 ) - if((rc = _cmScParseSectionColumn(p,i,j-1,p->sectList)) != kOkScRC ) - break; - - // the bar lines don't have times so set the time of the bar line to the - // time of the first event in the bar. - if( barEvtIdx != cmInvalidIdx && secs != DBL_MAX ) + if( rc == kOkScRC ) { - assert( p->array[ barEvtIdx ].type == kBarEvtScId ); - p->array[ barEvtIdx ].secs = secs; + if( secs != DBL_MAX ) + cur_secs = secs; - // handle the case where the previous bar had no events - // BUG BUG BUG this is a hack which will fail if the first bar does not have events. - if( barEvtIdx>=1 && p->array[ barEvtIdx-1].type == kBarEvtScId ) - p->array[ barEvtIdx-1].secs = secs; + // form the section list + if( j > 0 ) + if((rc = _cmScParseSectionColumn(p,i,j-1,p->sectList)) != kOkScRC ) + break; - barEvtIdx = cmInvalidIdx; + // the bar lines don't have times so set the time of the bar line to the + // time of the first event in the bar. + if( barEvtIdx != cmInvalidIdx && secs != DBL_MAX ) + { + assert( p->array[ barEvtIdx ].type == kBarEvtScId ); + p->array[ barEvtIdx ].secs = secs; + + // handle the case where the previous bar had no events + // BUG BUG BUG this is a hack which will fail if the first bar does not have events. + if( barEvtIdx>=1 && p->array[ barEvtIdx-1].type == kBarEvtScId ) + p->array[ barEvtIdx-1].secs = secs; + + barEvtIdx = cmInvalidIdx; + } } } @@ -1164,6 +1437,9 @@ cmScRC_t cmScoreInitialize( cmCtx_t* ctx, cmScH_t* hp, const cmChar_t* fn, doubl if((rc = _cmScProcSections(p,p->sectList)) != kOkScRC ) goto errLabel; + if((rc = _cmScProcMarkers(p)) != kOkScRC ) + goto errLabel; + // load the dynamic reference array if( dynRefArray != NULL && dynRefCnt > 0) { @@ -1409,6 +1685,30 @@ unsigned cmScoreSetCount( cmScH_t h ) return p->setCnt; } +unsigned cmScoreMarkerLabelCount( cmScH_t h ) +{ + cmSc_t* p = _cmScHandleToPtr(h); + return p->markLabelCnt; +} + +unsigned cmScoreMarkerLabelSymbolId( cmScH_t h, unsigned idx ) +{ + cmSc_t* p = _cmScHandleToPtr(h); + assert( idx < p->markLabelCnt ); + return p->markLabelArray[idx]; +} + +const cmScoreMarker_t* cmScoreMarker( cmScH_t h, cmMarkScMId_t markMId, unsigned labelSymId ) +{ + cmSc_t* p = _cmScHandleToPtr(h); + const cmScoreMarker_t* smp = NULL; + if( _cmScFindMarkLoc(p, markMId, labelSymId, &smp ) == NULL ) + return NULL; + + return smp; +} + + cmScRC_t cmScoreSeqNotify( cmScH_t h ) { cmScRC_t rc = kOkScRC; @@ -1502,7 +1802,7 @@ void _cmScPerfSortTimes( unsigned *v, unsigned n ) fl = true; } } - --n; + --n; } } @@ -1568,13 +1868,13 @@ bool _cmScPerfEven(cmSc_t* p, cmScoreSet_t* stp, bool printMissFl) if(printFl) { /* - for(i=0; ieleCnt; ++i) - { + for(i=0; ieleCnt; ++i) + { printf("%i %i ",i,v[i]); if( i > 0 ) - printf("%i ", d[i-1]); + printf("%i ", d[i-1]); printf("\n"); - } + } */ printf("%s EVENESS:%f\n",sortFl?"SORTED ":"",stp->value); } @@ -1955,6 +2255,214 @@ void cmScorePrint( cmScH_t h, cmRpt_t* rpt ) } } +cmScRC_t cmScoreFileFromMidi( cmCtx_t* ctx, const cmChar_t* midiFn, const cmChar_t* scoreFn ) +{ + cmScRC_t rc = kOkScRC; + cmMidiFileH_t mfH = cmMidiFileNullHandle; + cmCsvH_t csvH = cmCsvNullHandle; + cmErr_t err; + cmChar_t* titles[] = {"id","trk","evt","opcode","dticks","micros","status","meta","ch","d0","d1","arg0","arg1","bar","skip","even","grace","tempo","t frac","dyn","section","remark", NULL }; + + cmErrSetup(&err,&ctx->rpt,"MIDI to Score"); + + if( cmMidiFileOpen(midiFn, &mfH, ctx ) != kOkMfRC ) + return cmErrMsg(&err,kMidiFileFailScRC,"Unable to open the MIDI file '%s'.",midiFn); + + if( cmCsvInitialize(&csvH,ctx) != kOkCsvRC ) + { + cmErrMsg(&err,kCsvFailScRC,"Unable to initialize the CSV file: '%s'.",scoreFn); + goto errLabel; + } + + // Convert the track message 'dtick' field to delta-microseconds. + cmMidiFileTickToMicros(mfH); + + + unsigned msgCnt = cmMidiFileMsgCount(mfH); + unsigned i; + const cmMidiTrackMsg_t** tmpp = cmMidiFileMsgArray(mfH); + double acc_secs = 0; + unsigned lexTId = 0; + cmCsvCell_t* cp = NULL; + + + if( cmCsvAppendRow(csvH, &cp, cmCsvInsertSymText(csvH,titles[0]), kStrCsvTFl, lexTId ) != kOkCsvRC ) + { + cmErrMsg(&err,kCsvFailScRC,"Error inserting 'id' column in '%s'.",cmStringNullGuard(scoreFn)); + goto errLabel; + } + + for(i=1; titles[i]!=NULL; ++i) + { + if( cmCsvInsertTextColAfter(csvH, cp, &cp, titles[i], lexTId ) != kOkCsvRC ) + { + cmErrMsg(&err,kCsvFailScRC,"Error inserting column index '%i' label in '%s'.",i,cmStringNullGuard(scoreFn)); + goto errLabel; + } + + } + + + + for(i=0; idtick / 1000000.0; + + acc_secs += dsecs; + + if( tmp->status == kMetaStId ) + { + opStr = cmMidiMetaStatusToLabel(tmp->metaId); + metaId = tmp->metaId; + + switch( tmp->metaId ) + { + case kTempoMdId: + d0 = tmp->u.iVal; + } + } + else + { + opStr = cmMidiStatusToLabel(tmp->status); + if( cmMidiIsChStatus( tmp->status ) ) + { + midiCh = tmp->u.chMsgPtr->ch; + d0 = tmp->u.chMsgPtr->d0; + d1 = tmp->u.chMsgPtr->d1; + } + } + + cp = NULL; + + // skip note-off messages + if( tmp->status == kNoteOffMdId ) + continue; + + if( cmCsvAppendRow(csvH, &cp, cmCsvInsertSymUInt(csvH,i), kIntCsvTFl, lexTId ) != kOkCsvRC ) + { + cmErrMsg(&err,kCsvFailScRC,"Error inserting 'id' column in '%s'.",cmStringNullGuard(scoreFn)); + goto errLabel; + } + + if( cmCsvInsertUIntColAfter(csvH, cp, &cp, tmp->trkIdx, lexTId ) != kOkCsvRC ) + { + cmErrMsg(&err,kCsvFailScRC,"Error inserting 'trk' column in '%s'.",cmStringNullGuard(scoreFn)); + goto errLabel; + } + + if( cmCsvInsertUIntColAfter(csvH, cp, &cp, 0, lexTId ) != kOkCsvRC ) + { + cmErrMsg(&err,kCsvFailScRC,"Error inserting 'evt' column in '%s'.",cmStringNullGuard(scoreFn)); + goto errLabel; + } + + if( cmCsvInsertTextColAfter(csvH, cp, &cp, opStr, lexTId ) != kOkCsvRC ) + { + cmErrMsg(&err,kCsvFailScRC,"Error inserting 'opcode' column in '%s'.",cmStringNullGuard(scoreFn)); + goto errLabel; + } + + if( cmCsvInsertDoubleColAfter(csvH, cp, &cp, dsecs, lexTId ) != kOkCsvRC ) + { + cmErrMsg(&err,kCsvFailScRC,"Error inserting 'dticks' column in '%s'.",cmStringNullGuard(scoreFn)); + goto errLabel; + } + + if( cmCsvInsertDoubleColAfter(csvH, cp, &cp, acc_secs, lexTId ) != kOkCsvRC ) + { + cmErrMsg(&err,kCsvFailScRC,"Error inserting 'micros' column in '%s'.",cmStringNullGuard(scoreFn)); + goto errLabel; + } + + if( cmCsvInsertHexColAfter(csvH, cp, &cp, tmp->status, lexTId ) != kOkCsvRC ) + { + cmErrMsg(&err,kCsvFailScRC,"Error inserting 'status' column in '%s'.",cmStringNullGuard(scoreFn)); + goto errLabel; + } + + if( cmCsvInsertUIntColAfter(csvH, cp, &cp, metaId, lexTId ) != kOkCsvRC ) + { + cmErrMsg(&err,kCsvFailScRC,"Error inserting 'meta' column in '%s'.",cmStringNullGuard(scoreFn)); + goto errLabel; + } + + if( cmCsvInsertUIntColAfter(csvH, cp, &cp, midiCh, lexTId ) != kOkCsvRC ) + { + cmErrMsg(&err,kCsvFailScRC,"Error inserting 'ch' column in '%s'.",cmStringNullGuard(scoreFn)); + goto errLabel; + } + + if( cmCsvInsertUIntColAfter(csvH, cp, &cp, d0, lexTId ) != kOkCsvRC ) + { + cmErrMsg(&err,kCsvFailScRC,"Error inserting 'd0' column in '%s'.",cmStringNullGuard(scoreFn)); + goto errLabel; + } + + if( cmCsvInsertUIntColAfter(csvH, cp, &cp, d1, lexTId ) != kOkCsvRC ) + { + cmErrMsg(&err,kCsvFailScRC,"Error inserting 'd1' column in '%s'.",cmStringNullGuard(scoreFn)); + goto errLabel; + } + + switch( tmp->status ) + { + case kNoteOnMdId: + if( cmCsvInsertTextColAfter(csvH, cp, &cp, cmMidiToSciPitch(tmp->u.chMsgPtr->d0,NULL,0), lexTId ) != kOkCsvRC ) + { + cmErrMsg(&err,kCsvFailScRC,"Error inserting 'opcode' column in '%s'.",cmStringNullGuard(scoreFn)); + goto errLabel; + } + + case kMetaStId: + switch( tmp->metaId ) + { + case kTimeSigMdId: + if( cmCsvInsertUIntColAfter(csvH, cp, &cp, tmp->u.timeSigPtr->num, lexTId ) != kOkCsvRC ) + { + cmErrMsg(&err,kCsvFailScRC,"Error inserting time sign. numerator column in '%s'.",cmStringNullGuard(scoreFn)); + goto errLabel; + } + + if( cmCsvInsertUIntColAfter(csvH, cp, &cp, tmp->u.timeSigPtr->den, lexTId ) != kOkCsvRC ) + { + cmErrMsg(&err,kCsvFailScRC,"Error inserting time sign. denominator column in '%s'.",cmStringNullGuard(scoreFn)); + goto errLabel; + } + break; + + case kTempoMdId: + if( cmCsvInsertUIntColAfter(csvH, cp, &cp, 60000000/tmp->u.iVal, lexTId ) != kOkCsvRC ) + { + cmErrMsg(&err,kCsvFailScRC,"Error inserting 'tempo' in '%s'.",cmStringNullGuard(scoreFn)); + goto errLabel; + } + break; + } + + } + + + } + + if( cmCsvWrite(csvH,scoreFn) != kOkCsvRC ) + { + cmErrMsg(&err,kCsvFailScRC,"The score output file '%s' could not be written.",cmStringNullGuard(scoreFn)); + goto errLabel; + } + + errLabel: + cmMidiFileClose(&mfH); + cmCsvFinalize(&csvH); + + return rc; +} + void cmScoreTest( cmCtx_t* ctx, const cmChar_t* fn ) { cmScH_t h = cmScNullHandle; diff --git a/app/cmScore.h b/app/cmScore.h index 3c9e680..cccc7a4 100644 --- a/app/cmScore.h +++ b/app/cmScore.h @@ -12,8 +12,8 @@ extern "C" { kSyntaxErrScRC, kInvalidIdxScRC, kTimeLineFailScRC, - kInvalidDynRefCntScRC - + kInvalidDynRefCntScRC, + kMidiFileFailScRC }; enum @@ -36,12 +36,12 @@ extern "C" { // Flags used by cmScoreEvt_t.flags enum { - kEvenScFl = 0x01, // This note is marked for evenness measurement - kDynScFl = 0x02, // This note is marked for dynamics measurement - kTempoScFl = 0x04, // This note is marked for tempo measurement - kSkipScFl = 0x08, // This isn't a real event (e.g. tied note) skip over it - kGraceScFl = 0x10, // This is a grace note - kInvalidScFl = 0x20 // This note has a calculated time + kEvenScFl = 0x001, // This note is marked for evenness measurement + kDynScFl = 0x002, // This note is marked for dynamics measurement + kTempoScFl = 0x004, // This note is marked for tempo measurement + kSkipScFl = 0x008, // This isn't a real event (e.g. tied note) skip over it + kGraceScFl = 0x010, // This is a grace note + kInvalidScFl = 0x020 // This note has a calculated time }; @@ -103,7 +103,26 @@ extern "C" { double value; struct cmScoreSet_str* llink; // cmScoreLoc_t setList link } cmScoreSet_t; - + + typedef enum + { + kInvalidScMId, + kRecdBegScMId, + kRecdEndScMId, + kFadeScMId, + kPlayBegScMId, + kPlayEndScMId + } cmMarkScMId_t; + + // score markers + typedef struct cmScoreMarker_str + { + cmMarkScMId_t markTypeId; // marker type + unsigned labelSymId; // marker label + struct cmScoreLoc_str* scoreLocPtr; // score location of the marker + unsigned csvRowIdx; // score CSV file line assoc'd w/ this marker + struct cmScoreMarker_str* link; // cmScoreLoc_t.markList links + } cmScoreMarker_t; // All events which are simultaneous are collected into a single // cmScoreLoc_t record. @@ -116,6 +135,7 @@ extern "C" { unsigned barNumb; // Bar number this event is contained by. cmScoreSet_t* setList; // Set's which end on this time location (linked through cmScoreSet_t.llink) cmScoreSection_t* begSectPtr; // NULL if this location does not start a section + cmScoreMarker_t* markList; // List of markers assigned to this location } cmScoreLoc_t; typedef void (*cmScCb_t)( void* arg, const void* data, unsigned byteCnt ); @@ -170,6 +190,10 @@ extern "C" { // Return the count of sets. unsigned cmScoreSetCount( cmScH_t h ); + unsigned cmScoreMarkerLabelCount( cmScH_t h ); + unsigned cmScoreMarkerLabelSymbolId( cmScH_t h, unsigned idx ); + const cmScoreMarker_t* cmScoreMarker( cmScH_t h, cmMarkScMId_t markMId, unsigned labelSymId ); + // Make callbacks for all events in the score. The callbacks // contain cmScMsg_t records serialized as a byte stream. // Use cmScoreDecode() to convert the byte string to a @@ -235,6 +259,9 @@ extern "C" { void cmScorePrint( cmScH_t h, cmRpt_t* rpt ); + // Generate a new score file from a MIDI file. + cmScRC_t cmScoreFileFromMidi( cmCtx_t* ctx, const cmChar_t* midiFn, const cmChar_t* scoreFn ); + void cmScoreTest( cmCtx_t* ctx, const cmChar_t* fn ); diff --git a/cmCsv.c b/cmCsv.c index 5b594e3..e18373e 100644 --- a/cmCsv.c +++ b/cmCsv.c @@ -729,6 +729,20 @@ unsigned cmCsvInsertSymUInt( cmCsvH_t h, unsigned v ) return cmInvalidId; } +unsigned cmCsvInsertSymHex( cmCsvH_t h, unsigned v ) +{ + const char* fmt = "0x%x"; + unsigned n = snprintf(NULL,0,fmt,v)+1; + char buf[n]; + + buf[0]= 0; + if( snprintf(buf,n,fmt,v) == n-1 ) + return cmCsvInsertSymText(h,buf); + + _cmCsvError(_cmCsvHandleToPtr(h),kDataCvtErrCsvRC,"The unsigned int 0x%x could not be converted to text.",v); + return cmInvalidId; +} + unsigned cmCsvInsertSymFloat( cmCsvH_t h, float v ) { const char* fmt = "%f"; @@ -812,6 +826,24 @@ cmCsvRC_t cmCsvSetCellUInt( cmCsvH_t h, unsigned row, unsigned col, unsigned return kOkCsvRC; } +cmCsvRC_t cmCsvSetCellHex( cmCsvH_t h, unsigned row, unsigned col, unsigned v ) +{ + cmCsvCell_t* cp; + unsigned symId; + + if((cp = _cmCsvCellPtr(h,row,col)) == NULL ) + return cmErrLastRC(&_cmCsvHandleToPtr(h)->err); + + if((symId = cmCsvInsertSymHex(h,v)) == cmInvalidId ) + return cmErrLastRC(&_cmCsvHandleToPtr(h)->err); + + cp->symId = symId; + cp->flags &= !kTypeTMask; + cp->flags |= kIntCsvTFl; + + return kOkCsvRC; +} + cmCsvRC_t cmCsvSetCellFloat( cmCsvH_t h, unsigned row, unsigned col, float v ) { cmCsvCell_t* cp; @@ -985,7 +1017,7 @@ cmCsvRC_t cmCsvInsertTextColAfter( cmCsvH_t h, cmCsvCell_t* leftCellPtr, cmCs cmCsvCell_t* ncp; if( cellPtrPtr != NULL ) - cellPtrPtr = NULL; + *cellPtrPtr = NULL; if((rc = cmCsvInsertColAfter(h, leftCellPtr, &ncp, cmInvalidId, 0, lexTId )) == kOkCsvRC ) if((rc = cmCsvSetCellText(h, ncp->row, ncp->col, text )) == kOkCsvRC ) @@ -1001,7 +1033,7 @@ cmCsvRC_t cmCsvInsertIntColAfter( cmCsvH_t h, cmCsvCell_t* leftCellPtr, cmCs cmCsvCell_t* ncp; if( cellPtrPtr != NULL ) - cellPtrPtr = NULL; + *cellPtrPtr = NULL; if((rc = cmCsvInsertColAfter(h, leftCellPtr, &ncp, cmInvalidId, 0, lexTId )) == kOkCsvRC ) if((rc = cmCsvSetCellInt(h, ncp->row, ncp->col, val )) == kOkCsvRC ) @@ -1017,7 +1049,7 @@ cmCsvRC_t cmCsvInsertUIntColAfter( cmCsvH_t h, cmCsvCell_t* leftCellPtr, cmCs cmCsvCell_t* ncp; if( cellPtrPtr != NULL ) - cellPtrPtr = NULL; + *cellPtrPtr = NULL; if((rc = cmCsvInsertColAfter(h, leftCellPtr, &ncp, cmInvalidId, 0, lexTId )) == kOkCsvRC ) if((rc = cmCsvSetCellUInt(h, ncp->row, ncp->col, val )) == kOkCsvRC ) @@ -1027,13 +1059,29 @@ cmCsvRC_t cmCsvInsertUIntColAfter( cmCsvH_t h, cmCsvCell_t* leftCellPtr, cmCs return rc; } +cmCsvRC_t cmCsvInsertHexColAfter( cmCsvH_t h, cmCsvCell_t* leftCellPtr, cmCsvCell_t** cellPtrPtr, unsigned val, unsigned lexTId ) +{ + cmCsvRC_t rc; + cmCsvCell_t* ncp; + + if( cellPtrPtr != NULL ) + *cellPtrPtr = NULL; + + if((rc = cmCsvInsertColAfter(h, leftCellPtr, &ncp, cmInvalidId, 0, lexTId )) == kOkCsvRC ) + if((rc = cmCsvSetCellHex(h, ncp->row, ncp->col, val )) == kOkCsvRC ) + if( cellPtrPtr != NULL ) + *cellPtrPtr = ncp; + + return rc; +} + cmCsvRC_t cmCsvInsertFloatColAfter( cmCsvH_t h, cmCsvCell_t* leftCellPtr, cmCsvCell_t** cellPtrPtr, float val, unsigned lexTId ) { cmCsvRC_t rc; cmCsvCell_t* ncp; if( cellPtrPtr != NULL ) - cellPtrPtr = NULL; + *cellPtrPtr = NULL; if((rc = cmCsvInsertColAfter(h, leftCellPtr, &ncp, cmInvalidId, 0, lexTId )) == kOkCsvRC ) if((rc = cmCsvSetCellFloat(h, ncp->row, ncp->col, val )) == kOkCsvRC ) @@ -1049,7 +1097,7 @@ cmCsvRC_t cmCsvInsertDoubleColAfter( cmCsvH_t h, cmCsvCell_t* leftCellPtr, cmCs cmCsvCell_t* ncp; if( cellPtrPtr != NULL ) - cellPtrPtr = NULL; + *cellPtrPtr = NULL; if((rc = cmCsvInsertColAfter(h, leftCellPtr, &ncp, cmInvalidId, 0, lexTId )) == kOkCsvRC ) if((rc = cmCsvSetCellDouble(h, ncp->row, ncp->col, val )) == kOkCsvRC ) diff --git a/cmCsv.h b/cmCsv.h index d3b7b06..e686c1c 100644 --- a/cmCsv.h +++ b/cmCsv.h @@ -109,13 +109,16 @@ extern "C" { unsigned cmCsvInsertSymText( cmCsvH_t h, const char* text ); unsigned cmCsvInsertSymInt( cmCsvH_t h, int v ); unsigned cmCsvInsertSymUInt( cmCsvH_t h, unsigned v ); + unsigned cmCsvInsertSymHex( cmCsvH_t h, unsigned v ); unsigned cmCsvInsertSymFloat( cmCsvH_t h, float v ); unsigned cmCsvInsertSymDouble( cmCsvH_t h, double v ); + // Set the value associated with a cell. cmCsvRC_t cmCsvSetCellText( cmCsvH_t h, unsigned row, unsigned col, const char* text ); cmCsvRC_t cmCsvSetCellInt( cmCsvH_t h, unsigned row, unsigned col, int v ); cmCsvRC_t cmCsvSetCellUInt( cmCsvH_t h, unsigned row, unsigned col, unsigned v ); + cmCsvRC_t cmCsvSetCellHex( cmCsvH_t h, unsigned row, unsigned col, unsigned v ); cmCsvRC_t cmCsvSetCellFloat( cmCsvH_t h, unsigned row, unsigned col, float v ); cmCsvRC_t cmCsvSetCellDouble( cmCsvH_t h, unsigned row, unsigned col, double v ); @@ -134,6 +137,7 @@ extern "C" { cmCsvRC_t cmCsvInsertTextColAfter( cmCsvH_t h, cmCsvCell_t* leftCellPtr, cmCsvCell_t** cellPtrPtr, const char* val, unsigned lexTId ); cmCsvRC_t cmCsvInsertIntColAfter( cmCsvH_t h, cmCsvCell_t* leftCellPtr, cmCsvCell_t** cellPtrPtr, int val, unsigned lexTId ); cmCsvRC_t cmCsvInsertUIntColAfter( cmCsvH_t h, cmCsvCell_t* leftCellPtr, cmCsvCell_t** cellPtrPtr, unsigned val, unsigned lexTId ); + cmCsvRC_t cmCsvInsertHexColAfter( cmCsvH_t h, cmCsvCell_t* leftCellPtr, cmCsvCell_t** cellPtrPtr, unsigned val, unsigned lexTId ); cmCsvRC_t cmCsvInsertFloatColAfter( cmCsvH_t h, cmCsvCell_t* leftCellPtr, cmCsvCell_t** cellPtrPtr, float val, unsigned lexTId ); cmCsvRC_t cmCsvInsertDoubleColAfter( cmCsvH_t h, cmCsvCell_t* leftCellPtr, cmCsvCell_t** cellPtrPtr, double val, unsigned lexTId ); diff --git a/cmData.c b/cmData.c index b5725d0..db0cdae 100644 --- a/cmData.c +++ b/cmData.c @@ -4,32 +4,143 @@ #include "cmCtx.h" #include "cmMem.h" #include "cmMallocDebug.h" +#include "cmLinkedHeap.h" #include "cmData.h" +#include "cmLex.h" +#include "cmText.h" +#include "cmStack.h" -cmDtRC_t _cmDataErrNo = kOkDtRC; - -cmData_t cmDataNull = { kInvalidDtId,0,NULL,NULL,0 }; - -cmDtRC_t _cmDataSetError( unsigned err ) +typedef struct { - _cmDataErrNo = err; - return err; + cmDataTypeId_t typeId; + unsigned byteWidth; + const cmChar_t* label; +} cmDtTypeInfo_t; + +typedef struct +{ + cmDataContainerId_t id; + const cmChar_t* label; +} cmDtCntInfo_t; + +cmDtTypeInfo_t _cmDtTypeInfoArray[] = +{ + { kNullDtId, 0, "null" }, + { kUCharDtId, sizeof(unsigned char), "uchar" }, + { kCharDtId, sizeof(char), "char" }, + { kUShortDtId, sizeof(unsigned short), "ushort" }, + { kShortDtId, sizeof(short), "short" }, + { kUIntDtId, sizeof(unsigned int), "uint" }, + { kIntDtId, sizeof(int), "int" }, + { kULongDtId, sizeof(unsigned long), "ulong" }, + { kLongDtId, sizeof(long), "long" }, + { kFloatDtId, sizeof(float), "float" }, + { kDoubleDtId, sizeof(double), "double" }, + { kStrDtId, sizeof(char*), "string" }, + { kBlobDtId, sizeof(void*), "blob" }, + { kInvalidTypeDtId, 0, "" }, +}; + +cmDtCntInfo_t _cmDtCntInfoArray[] = +{ + { kScalarDtId, "scalar" }, + { kArrayDtId, "array" }, + { kListDtId, "list" }, + { kPairDtId, "pair" }, + { kRecordDtId, "record"}, + { kInvalidCntDtId,""} +}; + +cmData_t cmDataNull = { kInvalidTypeDtId,kInvalidCntDtId,0,NULL,NULL,0 }; + +cmDtRC_t _cmDtErrMsgV( const cmData_t* d, cmDtRC_t rc, const cmChar_t* fmt, va_list vl ) +{ + // REPLACE this with a global cmRpt call. + vprintf(fmt,vl); + return rc; } -void _cmDataFreeArray( cmData_t* p ) +cmDtRC_t _cmDtErrMsg( const cmData_t* d, cmDtRC_t rc, const cmChar_t* fmt, ... ) { - if(cmIsFlag(p->flags,kDynPtrDtFl)) + va_list vl; + va_start(vl,fmt); + rc = _cmDtErrMsgV(d,rc,fmt,vl); + va_end(vl); + return rc; +} + +const cmChar_t* cmDataTypeToLabel( cmDataTypeId_t tid ) +{ + unsigned i; + for(i=0; _cmDtTypeInfoArray[i].typeId!=kInvalidTypeDtId; ++i) + if( _cmDtTypeInfoArray[i].typeId == tid ) + return _cmDtTypeInfoArray[i].label; + return NULL; +} + +cmDataTypeId_t cmDataLabelToType( const cmChar_t* typeLabelStr ) +{ + unsigned i; + for(i=0; _cmDtTypeInfoArray[i].typeId!=kInvalidTypeDtId; ++i) + if( strcmp(_cmDtTypeInfoArray[i].label,typeLabelStr) == 0 ) + return _cmDtTypeInfoArray[i].typeId; + return kInvalidTypeDtId; +} + +unsigned cmDataByteWidth( cmDataTypeId_t tid ) +{ + unsigned i; + for(i=0; _cmDtTypeInfoArray[i].typeId!=kInvalidTypeDtId; ++i) + if( _cmDtTypeInfoArray[i].typeId == tid ) + return _cmDtTypeInfoArray[i].byteWidth; + return cmInvalidCnt; +} + +const cmChar_t* cmDataContainerIdToLabel( cmDataContainerId_t tid ) +{ + unsigned i; + for(i=0; _cmDtCntInfoArray[i].id!=kInvalidCntDtId; ++i) + if( _cmDtCntInfoArray[i].id == tid ) + return _cmDtCntInfoArray[i].label; + return NULL; +} + +cmDataContainerId_t cmDataLabelToContainerId( const cmChar_t* contLabelStr ) +{ + unsigned i; + for(i=0; _cmDtCntInfoArray[i].id!=kInvalidCntDtId; ++i) + if( strcmp(_cmDtCntInfoArray[i].label,contLabelStr) == 0 ) + return _cmDtCntInfoArray[i].id; + return kInvalidCntDtId; +} + +bool _cmDataIsDataOwner( const cmData_t* d ) +{ return cmIsFlag(d->flags,kFreeValueDtFl) && (d->cid==kArrayDtId || d->tid==kStrDtId || d->tid==kBlobDtId); } + + +cmDtRC_t _cmDataFreeData( cmData_t* d ) +{ + if( _cmDataIsDataOwner(d) ) { - cmMemFree(p->u.vp); - p->u.vp = NULL; - p->flags = cmClrFlag(p->flags,kDynPtrDtFl); + // A object marked with kFreeValueDtFl should never also be 'const. + // (??? is this true ???? ) + assert( cmIsNotFlag(d->flags,kConstValueDtFl) ); + + cmMemPtrFree(&d->u.vp); } - p->tid = kInvalidDtId; - p->cnt = 0; + + d->flags = cmClrFlag(d->flags,kFreeValueDtFl | kConstValueDtFl ); + d->tid = kNullDtId; // objects without data are always of type 'null'. + d->cnt = 0; + memset(&d->u,0,sizeof(d->u)); + return kOkDtRC; } void _cmDataFree( cmData_t* p ) { + if( p == NULL ) + return; + if( cmDataIsStruct(p) ) { cmData_t* cp = p->u.child; @@ -37,99 +148,414 @@ void _cmDataFree( cmData_t* p ) _cmDataFree(cp); } - _cmDataFreeArray(p); - if( cmIsFlag(p->flags,kDynObjDtFl) ) + _cmDataFreeData(p); + + if( cmIsFlag(p->flags,kFreeObjDtFl) ) cmMemFree(p); } -cmData_t* _cmDataAllocNode( cmData_t* parent, cmDataFmtId_t tid ) + +// Dynamically allocate a new data object. +cmData_t* _cmDataNew(cmData_t* parent, cmDataContainerId_t cid, cmDataTypeId_t tid) { - cmData_t* p = cmMemAllocZ(cmData_t,1); - p->tid = tid; - p->flags = kDynObjDtFl; - p->parent = parent; + cmData_t* d = cmMemAllocZ(cmData_t,1); + d->tid = tid; // objects without data are of type 'null'. + d->cid = cid; + d->flags = kFreeObjDtFl; + d->parent = parent; + d->cnt = 0; + if( parent != NULL ) - return cmDataAppendChild(parent,p); - return p; + cmDataAppendChild(parent,d); + + return d; } -unsigned _cmDataByteCount( const cmData_t* p ) +bool cmDataIsConstObj( const cmData_t* d ) +{ return cmIsFlag(d->flags,kConstObjDtFl); } + +void cmDataEnableConstObj( cmData_t* d, bool enaFl ) +{ d->flags = cmEnaFlag(d->flags,kConstObjDtFl,enaFl); } + +bool cmDataIsConstValue( const cmData_t* d ) +{ return cmIsFlag(d->flags,kConstValueDtFl); } + +void cmDataEnableConstValue( cmData_t* d, bool enaFl ) +{ d->flags = cmEnaFlag(d->flags,kConstValueDtFl,enaFl); } + +bool cmDataIsFreeValue( const cmData_t* d ) +{ return cmIsFlag(d->flags,kFreeValueDtFl); } + +void cmDataEnableFreeValue( cmData_t* d, bool enaFl ) +{ d->flags = cmEnaFlag(d->flags,kFreeValueDtFl,enaFl); } + +bool cmDataIsLeaf( const cmData_t* d) +{ return d->cid == kScalarDtId || d->cid == kArrayDtId; } + +bool cmDataIsStruct( const cmData_t* d ) +{ return !cmDataIsLeaf(d); } + + +cmDtRC_t cmDataNewScalar( cmData_t* parent, cmDataTypeId_t tid, unsigned flags, void* vp, unsigned byteCnt, cmData_t** ref ) { - unsigned n = 0; + cmDtRC_t rc; - switch( p->tid ) + if( ref != NULL ) + *ref = NULL; + + // create a scalar null object + cmData_t* d = _cmDataNew(parent,kScalarDtId,kNullDtId); + + if( tid!=kStrDtId && tid!=kBlobDtId ) { - case kInvalidDtId: return 0; - case kNullDtId: return n; - case kUCharDtId: return n + sizeof(unsigned char); - case kCharDtId: return n + sizeof(char); - case kUShortDtId: return n + sizeof(unsigned short); - case kShortDtId: return n + sizeof(short); - case kUIntDtId: return n + sizeof(unsigned int); - case kIntDtId: return n + sizeof(int); - case kULongDtId: return n + sizeof(unsigned long); - case kLongDtId: return n + sizeof(long); - case kFloatDtId: return n + sizeof(float); - case kDoubleDtId: return n + sizeof(double); - - case kStrDtId: return n + (p->u.z ==NULL ? 0 : strlen(p->u.z) + 1); - case kConstStrDtId: return n + (p->u.cz==NULL ? 0 : strlen(p->u.cz) + 1); + // When used with scalars kFreeValueDtFl and kNoCopyDtFl only + // has meaning for strings and blobs - so clear these flags for other types. + flags = cmClrFlag(flags,kFreeValueDtFl | kNoCopyDtFl); - case kUCharPtrDtId: return n + p->cnt * sizeof(unsigned char); - case kCharPtrDtId: return n + p->cnt * sizeof(char); - case kUShortPtrDtId: return n + p->cnt * sizeof(unsigned short); - case kShortPtrDtId: return n + p->cnt * sizeof(short); - case kUIntPtrDtId: return n + p->cnt * sizeof(unsigned int); - case kIntPtrDtId: return n + p->cnt * sizeof(int); - case kULongPtrDtId: return n + p->cnt * sizeof(unsigned long); - case kLongPtrDtId: return n + p->cnt * sizeof(long); - case kFloatPtrDtId: return n + p->cnt * sizeof(float); - case kDoublePtrDtId: return n + p->cnt * sizeof(double); - case kVoidPtrDtId: return n + p->cnt * sizeof(char); - - default: - return n; + // if this is not a blob or string then the byteCnt is reset + byteCnt = cmDataByteWidth(tid); } - assert(0); - return 0; + + + + // assign the value + if((rc = cmDataSetScalarValue(d,tid,vp,byteCnt,flags)) != kOkDtRC ) + return rc; + + // set the const flags for the new object + d->flags = cmSetFlag(d->flags, flags & (kConstValueDtFl | kConstObjDtFl)); + + if( ref != NULL ) + *ref = d; + + return rc; } -bool cmDataIsValue( const cmData_t* p ) -{ return kMinValDtId <= p->tid && p->tid <= kMaxValDtId; } +cmDtRC_t cmDataNewNull( cmData_t* parent, unsigned flags, cmData_t** ref ) +{ *ref = _cmDataNew(parent, kScalarDtId, kNullDtId); return kOkDtRC; } +cmDtRC_t cmDataNewChar( cmData_t* parent, unsigned flags, char v, cmData_t** ref ) +{ return cmDataNewScalar(parent,kCharDtId,flags,&v,0,ref); } +cmDtRC_t cmDataNewUChar( cmData_t* parent, unsigned flags, unsigned char v, cmData_t** ref ) +{ return cmDataNewScalar(parent,kUCharDtId,flags,&v,0,ref); } +cmDtRC_t cmDataNewShort( cmData_t* parent, unsigned flags, short v, cmData_t** ref ) +{ return cmDataNewScalar(parent,kShortDtId,flags,&v,0,ref); } +cmDtRC_t cmDataNewUShort( cmData_t* parent, unsigned flags, unsigned short v, cmData_t** ref ) +{ return cmDataNewScalar(parent,kUShortDtId,flags,&v,0,ref); } +cmDtRC_t cmDataNewInt( cmData_t* parent, unsigned flags, int v, cmData_t** ref ) +{ return cmDataNewScalar(parent,kIntDtId,flags,&v,0,ref); } +cmDtRC_t cmDataNewUInt( cmData_t* parent, unsigned flags, unsigned int v, cmData_t** ref ) +{ return cmDataNewScalar(parent,kUIntDtId,flags,&v,0,ref); } +cmDtRC_t cmDataNewLong( cmData_t* parent, unsigned flags, long v, cmData_t** ref ) +{ return cmDataNewScalar(parent,kLongDtId,flags,&v,0,ref); } +cmDtRC_t cmDataNewULong( cmData_t* parent, unsigned flags, unsigned long v, cmData_t** ref ) +{ return cmDataNewScalar(parent,kULongDtId,flags,&v,0,ref); } +cmDtRC_t cmDataNewFloat( cmData_t* parent, unsigned flags, float v, cmData_t** ref ) +{ return cmDataNewScalar(parent,kFloatDtId,flags,&v,0,ref); } +cmDtRC_t cmDataNewDouble( cmData_t* parent, unsigned flags, double v, cmData_t** ref ) +{ return cmDataNewScalar(parent,kDoubleDtId,flags,&v,0,ref); } +cmDtRC_t cmDataNewStr( cmData_t* parent, unsigned flags, cmChar_t* v, cmData_t** ref ) +{ return cmDataNewScalar(parent,kStrDtId,flags,v,strlen(v)+1,ref); } +cmDtRC_t cmDataNewConstStr( cmData_t* parent, unsigned flags, const cmChar_t* v, cmData_t** ref ) +{ return cmDataNewScalar(parent,kStrDtId,flags | kConstValueDtFl, (void*)v,strlen(v)+1,ref); } +cmDtRC_t cmDataNewStrN( cmData_t* parent, unsigned flags, cmChar_t* v, unsigned charCnt, cmData_t** ref ) +{ return cmDataNewScalar(parent,kStrDtId,flags,v,charCnt+1,ref); } +cmDtRC_t cmDataNewConstStrN( cmData_t* parent, unsigned flags, const cmChar_t* v, unsigned charCnt, cmData_t** ref ) +{ return cmDataNewScalar(parent,kStrDtId,flags | kConstValueDtFl, (void*)v,charCnt+1,ref); } +cmDtRC_t cmDataNewBlob( cmData_t* parent, unsigned flags, void* v, unsigned byteCnt, cmData_t** ref ) +{ return cmDataNewScalar(parent,kBlobDtId,flags,v,byteCnt,ref); } +cmDtRC_t cmDataNewConstBlob( cmData_t* parent, unsigned flags, const void* v, unsigned byteCnt, cmData_t** ref ) +{ return cmDataNewScalar(parent,kBlobDtId,flags | kConstValueDtFl, (void*)v,byteCnt,ref); } -bool cmDataIsPtr( const cmData_t* p ) -{ return kMinPtrDtId <= p->tid && p->tid <= kMaxPtrDtId; } -bool cmDataIsStruct( const cmData_t* p ) -{ return kMinStructDtId <= p->tid && p->tid <= kMaxStructDtId; } +cmDtRC_t cmDataSetScalarValue( cmData_t* d, cmDataTypeId_t tid, void* vp, unsigned byteCnt, unsigned flags ) +{ + cmDtRC_t rc; + + // if the type of the object is changing + if( d->tid != tid || d->cid != kScalarDtId ) + { + // verify that it is legal to change the type of the object + if( cmIsFlag(d->flags,kConstObjDtFl) ) + return _cmDtErrMsg(d,kConstErrDtRC,"Const object violation."); + + // convert this to a scalar null object. + if((rc = _cmDataFreeData(d)) != kOkDtRC ) + return rc; + } + + // verify that it is legal to change the value of this object + if( cmIsFlag(d->flags,kConstValueDtFl) ) + return _cmDtErrMsg(d,kConstErrDtRC,"Const value violation."); + + switch( tid ) + { + case kInvalidTypeDtId: + return _cmDtErrMsg(d,kAssertErrDtRC,"Invalid data type."); + + case kNullDtId: // 'd' is already NULL. + break; + + case kUCharDtId: d->u.uc = *(unsigned char*)vp; break; + case kCharDtId: d->u.c = *(char*)vp; break; + case kUShortDtId: d->u.us = *(unsigned short*)vp; break; + case kShortDtId: d->u.s = *(short*)vp; break; + case kUIntDtId: d->u.ui = *(unsigned int*)vp; break; + case kIntDtId: d->u.i = *(int*)vp; break; + case kULongDtId: d->u.ul = *(unsigned long*)vp; break; + case kLongDtId: d->u.l = *(long*)vp; break; + case kFloatDtId: d->u.f = *(float*)vp; break; + case kDoubleDtId: d->u.d = *(double*)vp; break; + case kStrDtId: + case kBlobDtId: + { + cmChar_t* blankStr = ""; + + // strings must have a byteCnt of at least one + assert( tid==kBlobDtId || (tid==kStrDtId && byteCnt>0) ); + + // if a NULL source string is encountered then make it a 0 length string + if( d->tid==kStrDtId && vp==NULL ) + vp = blankStr; + + // if an empty blob was passed in then be sure it's src ptr is NULL and byteCnt==0 + if( d->tid==kBlobDtId && (vp==NULL || byteCnt==0) ) + { + if((rc = _cmDataFreeData(d)) != kOkDtRC ) + return rc; + + byteCnt = 0; + d->u.z = NULL; + break; + } + + // if the incoming string/blob should be internally duplicated + if( cmIsNotFlag(flags,kNoCopyDtFl) ) + { + + // allocate internal space to store the incoming data + if( (d->tid==kBlobDtId || d->tid == kStrDtId) && cmIsFlag(d->flags,kFreeValueDtFl) ) + d->u.z = cmMemResize(char,d->u.z,byteCnt); + else + d->u.z = cmMemAlloc(char,byteCnt); + + // store the source string/blob into the internal memory buffer + memcpy(d->u.z,vp,byteCnt); + + // by default the system now takes responsibility for freeing this buffer + d->flags |= kFreeValueDtFl; + } + else // the incoming string/blob pointer is simply being assigned w/o duplication + { + // free the objects previous value ... + if((rc = _cmDataFreeData(d)) != kOkDtRC ) + return rc; + + // and assign the new value (without reallocating the string) + d->u.z = vp; + + d->flags = cmEnaFlag(d->flags,kFreeValueDtFl,cmIsFlag(flags,kFreeValueDtFl)); + d->flags |= kNoCopyDtFl; + } + } + break; + + default: + break; + } + + // we can't set this above because the string type relies + // on knowing the previous type of the object + d->cid = kScalarDtId; + d->tid = tid; + d->cnt = byteCnt; + return rc; +} + +cmDtRC_t cmDataSetNull( cmData_t* d ) +{ return cmDataSetScalarValue(d, kNullDtId, NULL, 0, kNoFlagsDtFl ); } +cmDtRC_t cmDataSetChar( cmData_t* d, char v ) +{ return cmDataSetScalarValue(d, kCharDtId, &v, 0, kNoFlagsDtFl ); } +cmDtRC_t cmDataSetUChar( cmData_t* d, unsigned char v ) +{ return cmDataSetScalarValue(d, kUCharDtId, &v, 0, kNoFlagsDtFl ); } +cmDtRC_t cmDataSetShort( cmData_t* d, short v ) +{ return cmDataSetScalarValue(d, kShortDtId, &v, 0, kNoFlagsDtFl ); } +cmDtRC_t cmDataSetUShort( cmData_t* d, unsigned short v ) +{ return cmDataSetScalarValue(d, kUShortDtId, &v, 0, kNoFlagsDtFl ); } +cmDtRC_t cmDataSetInt( cmData_t* d, int v ) +{ return cmDataSetScalarValue(d, kIntDtId, &v, 0, kNoFlagsDtFl ); } +cmDtRC_t cmDataSetUInt( cmData_t* d, unsigned int v ) +{ return cmDataSetScalarValue(d, kUIntDtId, &v, 0, kNoFlagsDtFl ); } +cmDtRC_t cmDataSetLong( cmData_t* d, long v ) +{ return cmDataSetScalarValue(d, kLongDtId, &v, 0, kNoFlagsDtFl ); } +cmDtRC_t cmDataSetULong( cmData_t* d, unsigned long v ) +{ return cmDataSetScalarValue(d, kULongDtId, &v, 0, kNoFlagsDtFl ); } +cmDtRC_t cmDataSetFloat( cmData_t* d, float v ) +{ return cmDataSetScalarValue(d, kFloatDtId, &v, 0, kNoFlagsDtFl ); } +cmDtRC_t cmDataSetDouble( cmData_t* d, double v ) +{ return cmDataSetScalarValue(d, kDoubleDtId, &v, 0, kNoFlagsDtFl ); } +cmDtRC_t cmDataSetStr( cmData_t* d, unsigned flags, cmChar_t* v ) +{ return cmDataSetScalarValue(d, kStrDtId, v, v==NULL ? 1 : strlen(v)+1, flags ); } +cmDtRC_t cmDataSetConstStr( cmData_t* d, unsigned flags, const cmChar_t* v ) +{ return cmDataSetScalarValue(d, kStrDtId, (void*)v, v==NULL ? 1 : strlen(v)+1, flags |= kConstValueDtFl ); } +cmDtRC_t cmDataSetStrN( cmData_t* d, unsigned flags, cmChar_t* v, unsigned charCnt ) +{ return cmDataSetScalarValue(d, kStrDtId, (void*)v, v==NULL ? 1 : charCnt+1, flags); } +cmDtRC_t cmDataSetConstStrN( cmData_t* d, unsigned flags, const cmChar_t* v, unsigned charCnt ) +{ return cmDataSetScalarValue(d, kStrDtId, (void*)v, v==NULL ? 1 : charCnt+1, flags |= kConstValueDtFl); } +cmDtRC_t cmDataSetBlob( cmData_t* d, unsigned flags, void* v, unsigned byteCnt ) +{ return cmDataSetScalarValue(d, kBlobDtId, v, byteCnt, flags); } +cmDtRC_t cmDataSetConstBlob( cmData_t* d, unsigned flags, const void* v, unsigned byteCnt ) +{ return cmDataSetScalarValue(d, kBlobDtId, (void*)v, byteCnt, flags |= kConstValueDtFl); } + + + +cmDtRC_t cmDataChar( const cmData_t* d, char* v ) +{ + if( d->tid != kCharDtId ) + return _cmDtErrMsg(d,kInvalidTypeDtRC,"Expected type:char but encountered type:%s.",cmDataTypeToLabel(d->tid)); + *v = d->u.c; + return kOkDtRC; +} + +cmDtRC_t cmDataUChar( const cmData_t* d, unsigned char* v ) +{ + if( d->tid != kUCharDtId ) + return _cmDtErrMsg(d,kInvalidTypeDtRC,"Expected type:uchar but encountered type:%s.",cmDataTypeToLabel(d->tid)); + *v = d->u.uc; + return kOkDtRC; +} + +cmDtRC_t cmDataShort( const cmData_t* d, short* v ) +{ + if( d->tid != kShortDtId ) + return _cmDtErrMsg(d,kInvalidTypeDtRC,"Expected type:short but encountered type:%s.",cmDataTypeToLabel(d->tid)); + *v = d->u.s; + return kOkDtRC; +} + +cmDtRC_t cmDataUShort( const cmData_t* d, unsigned short* v ) +{ + if( d->tid != kUShortDtId ) + return _cmDtErrMsg(d,kInvalidTypeDtRC,"Expected type:ushort but encountered type:%s.",cmDataTypeToLabel(d->tid)); + *v = d->u.us; + return kOkDtRC; +} + +cmDtRC_t cmDataInt( const cmData_t* d, int* v ) +{ + if( d->tid != kIntDtId ) + return _cmDtErrMsg(d,kInvalidTypeDtRC,"Expected type:int but encountered type:%s.",cmDataTypeToLabel(d->tid)); + *v = d->u.i; + return kOkDtRC; +} + +cmDtRC_t cmDataUInt( const cmData_t* d, unsigned int* v ) +{ + if( d->tid != kUIntDtId ) + return _cmDtErrMsg(d,kInvalidTypeDtRC,"Expected type:uint but encountered type:%s.",cmDataTypeToLabel(d->tid)); + *v = d->u.ui; + return kOkDtRC; +} + +cmDtRC_t cmDataLong( const cmData_t* d, long* v ) +{ + if( d->tid != kLongDtId ) + return _cmDtErrMsg(d,kInvalidTypeDtRC,"Expected type:long but encountered type:%s.",cmDataTypeToLabel(d->tid)); + *v = d->u.l; + return kOkDtRC; +} + +cmDtRC_t cmDataULong( const cmData_t* d, unsigned long* v ) +{ + if( d->tid != kULongDtId ) + return _cmDtErrMsg(d,kInvalidTypeDtRC,"Expected type:ulong but encountered type:%s.",cmDataTypeToLabel(d->tid)); + *v = d->u.ul; + return kOkDtRC; +} + +cmDtRC_t cmDataFloat( const cmData_t* d, float* v ) +{ + if( d->tid != kFloatDtId ) + return _cmDtErrMsg(d,kInvalidTypeDtRC,"Expected type:float but encountered type:%s.",cmDataTypeToLabel(d->tid)); + *v = d->u.f; + return kOkDtRC; +} + +cmDtRC_t cmDataDouble( const cmData_t* d, double* v ) +{ + if( d->tid != kDoubleDtId ) + return _cmDtErrMsg(d,kInvalidTypeDtRC,"Expected type:double but encountered type:%s.",cmDataTypeToLabel(d->tid)); + *v = d->u.d; + return kOkDtRC; +} + +cmDtRC_t cmDataStr( const cmData_t* d, cmChar_t** v ) +{ + if( d->tid != kStrDtId ) + return _cmDtErrMsg(d,kInvalidTypeDtRC,"Expected type:string but encountered type:%s.",cmDataTypeToLabel(d->tid)); + + if( cmIsFlag(d->flags,kConstValueDtFl) ) + return _cmDtErrMsg(d,kConstErrDtRC,"A const string cannot return as a non-const string."); + + *v = d->u.z; + return kOkDtRC; +} + +cmDtRC_t cmDataConstStr( const cmData_t* d, const cmChar_t** v ) +{ + if( d->tid != kStrDtId ) + return _cmDtErrMsg(d,kInvalidTypeDtRC,"Expected type:string but encountered type:%s.",cmDataTypeToLabel(d->tid)); + + *v = d->u.z; + return kOkDtRC; +} + +cmDtRC_t cmDataBlob( const cmData_t* d, cmChar_t** v, unsigned* byteCntRef ) +{ + if( v != NULL ) + *v = NULL; + + if( byteCntRef != NULL ) + *byteCntRef = 0; + + if( d->tid != kBlobDtId ) + return _cmDtErrMsg(d,kInvalidTypeDtRC,"Expected type:string but encountered type:%s.",cmDataTypeToLabel(d->tid)); + + if( v != NULL ) + *v = d->u.z; + + if( byteCntRef != NULL ) + *byteCntRef = d->cnt; + + return kOkDtRC; +} + +cmDtRC_t cmDataConstBlob( const cmData_t* d, const cmChar_t** v, unsigned* byteCntRef ) +{ + if( v != NULL ) + *v = NULL; + + if( byteCntRef != NULL ) + *byteCntRef = 0; + + if( d->tid != kBlobDtId ) + return _cmDtErrMsg(d,kInvalidTypeDtRC,"Expected type:string but encountered type:%s.",cmDataTypeToLabel(d->tid)); + + if( v != NULL ) + *v = d->u.z; + + if( byteCntRef != NULL ) + *byteCntRef = d->cnt; + + return kOkDtRC; +} -char cmDataChar( const cmData_t* p ) { assert(p->tid==kCharDtId); return p->u.c; } -unsigned char cmDataUChar( const cmData_t* p ) { assert(p->tid==kUCharDtId); return p->u.uc; } -short cmDataShort( const cmData_t* p ) { assert(p->tid==kShortDtId); return p->u.s; } -unsigned short cmDataUShort( const cmData_t* p ) { assert(p->tid==kUShortDtId); return p->u.us; } -int cmDataInt( const cmData_t* p ) { assert(p->tid==kIntDtId); return p->u.i; } -unsigned int cmDataUInt( const cmData_t* p ) { assert(p->tid==kUIntDtId); return p->u.ui; } -long cmDataLong( const cmData_t* p ) { assert(p->tid==kLongDtId); return p->u.l; } -unsigned long cmDataULong( const cmData_t* p ) { assert(p->tid==kULongDtId); return p->u.ul; } -float cmDataFloat( const cmData_t* p ) { assert(p->tid==kFloatDtId); return p->u.f; } -double cmDataDouble( const cmData_t* p ) { assert(p->tid==kDoubleDtId); return p->u.d; } -cmChar_t* cmDataStr( const cmData_t* p ) { assert(p->tid==kStrDtId); return p->u.z; } -const cmChar_t* cmDataConstStr( const cmData_t* p ) { assert(p->tid==kConstStrDtId); return p->u.cz; } -void* cmDataVoidPtr( const cmData_t* p ) { assert(p->tid==kVoidPtrDtId); return p->u.vp; } -char* cmDataCharPtr( const cmData_t* p ) { assert(p->tid==kCharPtrDtId); return p->u.cp; } -unsigned char* cmDataUCharPtr( const cmData_t* p ) { assert(p->tid==kUCharPtrDtId); return p->u.ucp; } -short* cmDataShortPtr( const cmData_t* p ) { assert(p->tid==kShortPtrDtId); return p->u.sp; } -unsigned short* cmDataUShortPtr( const cmData_t* p ) { assert(p->tid==kUShortPtrDtId); return p->u.usp; } -int* cmDataIntPtr( const cmData_t* p ) { assert(p->tid==kIntPtrDtId); return p->u.ip; } -unsigned int* cmDataUIntPtr( const cmData_t* p ) { assert(p->tid==kUIntPtrDtId); return p->u.uip; } -long* cmDataLongPtr( const cmData_t* p ) { assert(p->tid==kLongPtrDtId); return p->u.lp; } -unsigned long* cmDataULongPtr( const cmData_t* p ) { assert(p->tid==kULongPtrDtId); return p->u.ulp; } -float* cmDataFloatPtr( const cmData_t* p ) { assert(p->tid==kFloatPtrDtId); return p->u.fp; } -double* cmDataDoublePtr( const cmData_t* p ) { assert(p->tid==kDoublePtrDtId); return p->u.dp; } cmDtRC_t cmDataGetUChar( const cmData_t* p, unsigned char* vp ) { + if( p->cid != kScalarDtId ) + return _cmDtErrMsg(p,kInvalidContDtRC,"Cannot convert a non-scalar value to a scalar value."); + switch( p->tid ) { case kUCharDtId: *vp = p->u.uc; break; @@ -143,13 +569,16 @@ cmDtRC_t cmDataGetUChar( const cmData_t* p, unsigned char* vp ) case kFloatDtId: *vp = (unsigned char)p->u.f; break; case kDoubleDtId: *vp = (unsigned char)p->u.d; break; default: - return _cmDataSetError(kCvtErrDtRC); + return _cmDtErrMsg(p,kCvtErrDtRC,"Cannot convert '%s' to 'uchar'.",cmDataTypeToLabel(p->tid)); } return kOkDtRC; } cmDtRC_t cmDataGetChar( const cmData_t* p, char* vp ) { + if( p->cid != kScalarDtId ) + return _cmDtErrMsg(p,kInvalidContDtRC,"Cannot convert a non-scalar value to a scalar value."); + switch( p->tid ) { case kUCharDtId: *vp = (char)p->u.uc; break; @@ -163,13 +592,16 @@ cmDtRC_t cmDataGetChar( const cmData_t* p, char* vp ) case kFloatDtId: *vp = (char)p->u.f; break; case kDoubleDtId: *vp = (char)p->u.d; break; default: - return _cmDataSetError(kCvtErrDtRC); + return _cmDtErrMsg(p,kCvtErrDtRC,"Cannot convert '%s' to 'char'.",cmDataTypeToLabel(p->tid)); } return kOkDtRC; } cmDtRC_t cmDataGetShort( const cmData_t* p, short* vp ) { + if( p->cid != kScalarDtId ) + return _cmDtErrMsg(p,kInvalidContDtRC,"Cannot convert a non-scalar value to a scalar value."); + switch( p->tid ) { case kUCharDtId: *vp = (short)p->u.uc; break; @@ -183,7 +615,8 @@ cmDtRC_t cmDataGetShort( const cmData_t* p, short* vp ) case kFloatDtId: *vp = (short)p->u.f; break; case kDoubleDtId: *vp = (short)p->u.d; break; default: - return _cmDataSetError(kCvtErrDtRC); + return _cmDtErrMsg(p,kCvtErrDtRC,"Cannot convert '%s' to 'short'.",cmDataTypeToLabel(p->tid)); + } return kOkDtRC; } @@ -191,6 +624,9 @@ cmDtRC_t cmDataGetShort( const cmData_t* p, short* vp ) cmDtRC_t cmDataGetUShort( const cmData_t* p, unsigned short* vp ) { + if( p->cid != kScalarDtId ) + return _cmDtErrMsg(p,kInvalidContDtRC,"Cannot convert a non-scalar value to a scalar value."); + switch( p->tid ) { case kUCharDtId: *vp = (unsigned short)p->u.uc; break; @@ -204,13 +640,16 @@ cmDtRC_t cmDataGetUShort( const cmData_t* p, unsigned short* vp ) case kFloatDtId: *vp = (unsigned short)p->u.f; break; case kDoubleDtId: *vp = (unsigned short)p->u.d; break; default: - return _cmDataSetError(kCvtErrDtRC); + return _cmDtErrMsg(p,kCvtErrDtRC,"Cannot convert '%s' to 'ushort'.",cmDataTypeToLabel(p->tid)); + } return kOkDtRC; } cmDtRC_t cmDataGetInt( const cmData_t* p, int* vp ) { + if( p->cid != kScalarDtId ) + return _cmDtErrMsg(p,kInvalidContDtRC,"Cannot convert a non-scalar value to a scalar value."); switch( p->tid ) { @@ -225,13 +664,17 @@ cmDtRC_t cmDataGetInt( const cmData_t* p, int* vp ) case kFloatDtId: *vp = (int)p->u.f; break; case kDoubleDtId: *vp = (int)p->u.d; break; default: - return _cmDataSetError(kCvtErrDtRC); + return _cmDtErrMsg(p,kCvtErrDtRC,"Cannot convert '%s' to 'int'.",cmDataTypeToLabel(p->tid)); + } return kOkDtRC; } cmDtRC_t cmDataGetUInt( const cmData_t* p, unsigned int* vp ) { + if( p->cid != kScalarDtId ) + return _cmDtErrMsg(p,kInvalidContDtRC,"Cannot convert a non-scalar value to a scalar value."); + switch( p->tid ) { case kUCharDtId: *vp = (unsigned int)p->u.uc; break; @@ -245,13 +688,17 @@ cmDtRC_t cmDataGetUInt( const cmData_t* p, unsigned int* vp ) case kFloatDtId: *vp = (unsigned int)p->u.f; break; case kDoubleDtId: *vp = (unsigned int)p->u.d; break; default: - return _cmDataSetError(kCvtErrDtRC); + return _cmDtErrMsg(p,kCvtErrDtRC,"Cannot convert '%s' to 'uint'.",cmDataTypeToLabel(p->tid)); + } return kOkDtRC; } cmDtRC_t cmDataGetLong( const cmData_t* p, long* vp ) { + if( p->cid != kScalarDtId ) + return _cmDtErrMsg(p,kInvalidContDtRC,"Cannot convert a non-scalar value to a scalar value."); + switch( p->tid ) { case kUCharDtId: *vp = (long)p->u.uc; break; @@ -265,13 +712,17 @@ cmDtRC_t cmDataGetLong( const cmData_t* p, long* vp ) case kFloatDtId: *vp = (long)p->u.f; break; case kDoubleDtId: *vp = (long)p->u.d; break; default: - return _cmDataSetError(kCvtErrDtRC); + return _cmDtErrMsg(p,kCvtErrDtRC,"Cannot convert '%s' to 'long'.",cmDataTypeToLabel(p->tid)); + } return kOkDtRC; } cmDtRC_t cmDataGetULong( const cmData_t* p, unsigned long* vp ) { + if( p->cid != kScalarDtId ) + return _cmDtErrMsg(p,kInvalidContDtRC,"Cannot convert a non-scalar value to a scalar value."); + switch( p->tid ) { case kUCharDtId: *vp = (unsigned long)p->u.uc; break; @@ -285,13 +736,16 @@ cmDtRC_t cmDataGetULong( const cmData_t* p, unsigned long* vp ) case kFloatDtId: *vp = (unsigned long)p->u.f; break; case kDoubleDtId: *vp = (unsigned long)p->u.d; break; default: - return _cmDataSetError(kCvtErrDtRC); + return _cmDtErrMsg(p,kCvtErrDtRC,"Cannot convert '%s' to 'ulong'.",cmDataTypeToLabel(p->tid)); + } return kOkDtRC; } cmDtRC_t cmDataGetFloat( const cmData_t* p, float* vp ) { + if( p->cid != kScalarDtId ) + return _cmDtErrMsg(p,kInvalidContDtRC,"Cannot convert a non-scalar value to a scalar value."); switch( p->tid ) { @@ -306,13 +760,17 @@ cmDtRC_t cmDataGetFloat( const cmData_t* p, float* vp ) case kFloatDtId: *vp = p->u.f; break; case kDoubleDtId: *vp = (float)p->u.d; break; default: - return _cmDataSetError(kCvtErrDtRC); + return _cmDtErrMsg(p,kCvtErrDtRC,"Cannot convert '%s' to 'float'.",cmDataTypeToLabel(p->tid)); + } return kOkDtRC; } cmDtRC_t cmDataGetDouble( const cmData_t* p, double* vp ) { + if( p->cid != kScalarDtId ) + return _cmDtErrMsg(p,kInvalidContDtRC,"Cannot convert a non-scalar value to a scalar value."); + switch( p->tid ) { case kUCharDtId: *vp = (double)p->u.uc; break; @@ -326,797 +784,247 @@ cmDtRC_t cmDataGetDouble( const cmData_t* p, double* vp ) case kFloatDtId: *vp = (double)p->u.f; break; case kDoubleDtId: *vp = p->u.d; break; default: - return _cmDataSetError(kCvtErrDtRC); + return _cmDtErrMsg(p,kCvtErrDtRC,"Cannot convert '%s' to 'double'.",cmDataTypeToLabel(p->tid)); + } return kOkDtRC; } -cmDtRC_t cmDataGetStr( const cmData_t* p, cmChar_t** vp ) -{ - if( p->tid == kStrDtId || p->tid == kConstStrDtId) +cmDtRC_t cmDataNewArray( cmData_t* parent, cmDataTypeId_t tid, void* vp, unsigned eleCnt, unsigned flags, cmData_t** ref ) +{ + cmDtRC_t rc; + + if( ref != NULL ) + *ref = NULL; + + // create a new 'null' object + cmData_t* d = _cmDataNew(parent, kScalarDtId, kNullDtId ); + + // assign the value + if((rc = cmDataSetArrayValue(d,tid,vp,eleCnt,flags)) != kOkDtRC ) + return rc; + + // set the flags for the new object + d->flags = cmSetFlag(d->flags, flags & (kConstValueDtFl | kConstObjDtFl | kNoCopyDtFl)); + + if( ref != NULL ) + *ref = d; + + return rc; + +} + +cmDtRC_t cmDataNewCharArray( cmData_t* parent, char* v, unsigned eleCnt, unsigned flags, cmData_t** ref ) +{ return cmDataNewArray(parent, kCharDtId, v, eleCnt, flags, ref ); } +cmDtRC_t cmDataNewUCharArray( cmData_t* parent, unsigned char* v, unsigned eleCnt, unsigned flags, cmData_t** ref ) +{ return cmDataNewArray(parent, kUCharDtId, v, eleCnt, flags, ref ); } +cmDtRC_t cmDataNewShortArray( cmData_t* parent, short* v, unsigned eleCnt, unsigned flags, cmData_t** ref ) +{ return cmDataNewArray(parent, kShortDtId, v, eleCnt, flags, ref ); } +cmDtRC_t cmDataNewUShortArray( cmData_t* parent, unsigned short* v, unsigned eleCnt, unsigned flags, cmData_t** ref ) +{ return cmDataNewArray(parent, kUShortDtId, v, eleCnt, flags, ref ); } +cmDtRC_t cmDataNewIntArray( cmData_t* parent, int* v, unsigned eleCnt, unsigned flags, cmData_t** ref ) +{ return cmDataNewArray(parent, kIntDtId, v, eleCnt, flags, ref ); } +cmDtRC_t cmDataNewUIntArray( cmData_t* parent, unsigned int* v, unsigned eleCnt, unsigned flags, cmData_t** ref ) +{ return cmDataNewArray(parent, kUIntDtId, v, eleCnt, flags, ref ); } +cmDtRC_t cmDataNewLongArray( cmData_t* parent, long* v, unsigned eleCnt, unsigned flags, cmData_t** ref ) +{ return cmDataNewArray(parent, kLongDtId, v, eleCnt, flags, ref ); } +cmDtRC_t cmDataNewULongArray( cmData_t* parent, unsigned long* v, unsigned eleCnt, unsigned flags, cmData_t** ref ) +{ return cmDataNewArray(parent, kULongDtId, v, eleCnt, flags, ref ); } +cmDtRC_t cmDataNewFloatArray( cmData_t* parent, float* v, unsigned eleCnt, unsigned flags, cmData_t** ref ) +{ return cmDataNewArray(parent, kFloatDtId, v, eleCnt, flags, ref ); } +cmDtRC_t cmDataNewDoubleArray( cmData_t* parent, double* v, unsigned eleCnt, unsigned flags, cmData_t** ref ) +{ return cmDataNewArray(parent, kDoubleDtId, v, eleCnt, flags, ref ); } +cmDtRC_t cmDataNewStrArray( cmData_t* parent, cmChar_t** v, unsigned eleCnt, unsigned flags, cmData_t** ref ) +{ return cmDataNewArray(parent, kStrDtId, v, eleCnt, flags, ref ); } +cmDtRC_t cmDataNewConstStrArray( cmData_t* parent, const cmChar_t** v,unsigned eleCnt, unsigned flags, cmData_t** ref ) +{ return cmDataNewArray(parent, kStrDtId, (cmChar_t**)v, eleCnt, flags, ref ); } + + +cmDtRC_t cmDataSetArrayValue( cmData_t* d, cmDataTypeId_t tid, void* vp, unsigned eleCnt, unsigned flags ) +{ + cmDtRC_t rc = kOkDtRC; + + // if the type of the object is changing + if( d->tid != tid || d->cid != kScalarDtId ) { - *vp = (p->tid == kStrDtId || p->tid == kConstStrDtId) ? p->u.z : NULL; - return kOkDtRC; - } - return _cmDataSetError(kCvtErrDtRC); -} + // verify that it is legal to change the type of the object + if( cmIsFlag(d->flags,kConstObjDtFl) ) + return _cmDtErrMsg(d,kConstErrDtRC,"Const object violation."); -cmDtRC_t cmDataGetConstStr( const cmData_t* p, const cmChar_t** vp ) -{ - if( p->tid == kStrDtId || p->tid == kConstStrDtId) + // convert this to a scalar null object. + if((rc = _cmDataFreeData(d)) != kOkDtRC ) + return rc; + } + + // verify that it is legal to change the value of this object + if( cmIsFlag(d->flags,kConstValueDtFl) ) + return _cmDtErrMsg(d,kConstErrDtRC,"Const value violation."); + + + // if the array should be reallocated + if( cmIsNotFlag(flags,kNoCopyDtFl) ) { - *vp = (p->tid == kStrDtId || p->tid == kConstStrDtId) ? p->u.cz : NULL; - return kOkDtRC; + unsigned byteCnt = cmDataByteWidth(tid) * eleCnt; + + // reallocate a new string + if( d->cid == kArrayDtId && cmIsFlag(d->flags,kFreeValueDtFl) ) + d->u.vp = cmMemResize(char,d->u.z,byteCnt); + else + d->u.vp = cmMemAlloc(char,byteCnt); + + memcpy(d->u.z,vp,byteCnt); + + d->flags |= kFreeValueDtFl; } - return _cmDataSetError(kCvtErrDtRC); -} - -cmDtRC_t cmDataGetVoidPtr( const cmData_t* p, void** vp ) -{ - if( kMinPtrDtId <= p->tid && p->tid <= kMaxPtrDtId ) - { - *vp = ( kMinPtrDtId <= p->tid && p->tid <= kMaxPtrDtId ) ? p->u.vp : NULL; - return kOkDtRC; - } - return _cmDataSetError(kCvtErrDtRC); -} - -cmDtRC_t cmDataGetCharPtr( const cmData_t* p, char** vp ) -{ - if( p->tid == kCharPtrDtId || p->tid == kUCharPtrDtId ) - { - *vp = (p->tid == kCharPtrDtId || p->tid == kUCharPtrDtId) ? p->u.cp : NULL; - return kOkDtRC; - } - return _cmDataSetError(kCvtErrDtRC); -} - -cmDtRC_t cmDataGetUCharPtr( const cmData_t* p, unsigned char** vp ) -{ - if( p->tid == kCharPtrDtId || p->tid == kUCharPtrDtId ) - { - *vp = (p->tid == kCharPtrDtId || p->tid == kUCharPtrDtId) ? p->u.ucp : NULL; - return kOkDtRC; - } - return _cmDataSetError(kCvtErrDtRC); -} - -cmDtRC_t cmDataGetShortPtr( const cmData_t* p, short** vp ) -{ - if( p->tid == kShortPtrDtId || p->tid == kUShortPtrDtId ) - { - *vp = (p->tid == kShortPtrDtId || p->tid == kUShortPtrDtId ) ? p->u.sp : NULL; - return kOkDtRC; - } - return _cmDataSetError(kCvtErrDtRC); -} - -cmDtRC_t cmDataGetUShortPtr( const cmData_t* p, unsigned short** vp ) -{ - if( p->tid == kShortPtrDtId || p->tid == kUShortPtrDtId ) - { - *vp = (p->tid == kShortPtrDtId || p->tid == kUShortPtrDtId ) ? p->u.usp : NULL; - return kOkDtRC; - } - return _cmDataSetError(kCvtErrDtRC); -} - -cmDtRC_t cmDataGetIntPtr( const cmData_t* p, int** vp ) -{ - if( p->tid == kIntPtrDtId || p->tid == kUIntPtrDtId ) - { - *vp = (p->tid == kIntPtrDtId || p->tid == kUIntPtrDtId ) ? p->u.ip : NULL; - return kOkDtRC; - } - return _cmDataSetError(kCvtErrDtRC); -} - -cmDtRC_t cmDataGetUIntPtr( const cmData_t* p, unsigned int** vp ) -{ - if( p->tid == kIntPtrDtId || p->tid == kUIntPtrDtId ) - { - *vp = (p->tid == kIntPtrDtId || p->tid == kUIntPtrDtId ) ? p->u.uip : NULL; - return kOkDtRC; - } - return _cmDataSetError(kCvtErrDtRC); -} - -cmDtRC_t cmDataGetLongPtr( const cmData_t* p, long** vp ) -{ - if( p->tid == kLongPtrDtId || p->tid == kULongPtrDtId ) - { - *vp = (p->tid == kLongPtrDtId || p->tid == kULongPtrDtId ) ? p->u.lp : NULL; - return kOkDtRC; - } - return _cmDataSetError(kCvtErrDtRC); -} - -cmDtRC_t cmDataGetULongPtr( const cmData_t* p, unsigned long** vp ) -{ - if( p->tid == kLongPtrDtId || p->tid == kULongPtrDtId ) - { - *vp = (p->tid == kLongPtrDtId || p->tid == kULongPtrDtId ) ? p->u.ulp : NULL; - return kOkDtRC; - } - return _cmDataSetError(kCvtErrDtRC); -} - -cmDtRC_t cmDataGetFloatPtr( const cmData_t* p, float** vp ) -{ - if( p->tid == kFloatPtrDtId ) - { - *vp = p->u.fp; - return kOkDtRC; - } - return _cmDataSetError(kCvtErrDtRC); -} - -cmDtRC_t cmDataGetDoublePtr( const cmData_t* p, double** vp ) -{ - if( p->tid == kDoublePtrDtId ) - { - *vp = p->u.dp; - return kOkDtRC; - } - return _cmDataSetError(kCvtErrDtRC); -} - -// Set the value of an existing data object. -cmData_t* cmDataSetNull( cmData_t* p ) -{ - _cmDataFreeArray(p); - p->tid = kNullDtId; - return p; -} - -cmData_t* cmDataSetChar( cmData_t* p, char v ) -{ - _cmDataFreeArray(p); - p->tid = kCharDtId; - p->u.c = v; - return p; -} - -cmData_t* cmDataSetUChar( cmData_t* p, unsigned char v ) -{ - _cmDataFreeArray(p); - p->tid = kUCharDtId; - p->u.uc = v; - return p; -} - -cmData_t* cmDataSetShort( cmData_t* p, short v ) -{ - _cmDataFreeArray(p); - p->tid = kShortDtId; - p->u.s = v; - return p; -} - -cmData_t* cmDataSetUShort( cmData_t* p, unsigned short v ) -{ - _cmDataFreeArray(p); - p->tid = kUShortDtId; - p->u.us = v; - return p; -} - -cmData_t* cmDataSetInt( cmData_t* p, int v ) -{ - _cmDataFreeArray(p); - p->tid = kCharDtId; - p->u.c = v; - return p; -} - -cmData_t* cmDataSetUInt( cmData_t* p, unsigned int v ) -{ - _cmDataFreeArray(p); - p->tid = kUIntDtId; - p->u.ui = v; - return p; -} - -cmData_t* cmDataSetLong( cmData_t* p, long v ) -{ - _cmDataFreeArray(p); - p->tid = kLongDtId; - p->u.l = v; - return p; -} - -cmData_t* cmDataSetULong( cmData_t* p, unsigned long v ) -{ - _cmDataFreeArray(p); - p->tid = kULongDtId; - p->u.ul = v; - return p; -} - -cmData_t* cmDataSetFloat( cmData_t* p, float v ) -{ - _cmDataFreeArray(p); - p->tid = kFloatDtId; - p->u.f = v; - return p; -} - -cmData_t* cmDataSetDouble( cmData_t* p, double v ) -{ - _cmDataFreeArray(p); - p->tid = kDoubleDtId; - p->u.d = v; - return p; -} - -cmData_t* cmDataSetStr( cmData_t* p, cmChar_t* s ) -{ - _cmDataFreeArray(p); - p->tid = kStrDtId; - p->u.z = s; - return p; -} - -cmData_t* cmDataSetConstStr( cmData_t* p, const cmChar_t* s ) -{ - _cmDataFreeArray(p); - p->tid = kConstStrDtId; - p->u.cz = s; - return p; -} - -// Set the value of an existing data object to an external array. -// The array is not copied. -cmData_t* cmDataSetVoidPtr( cmData_t* p, void* vp, unsigned cnt ) -{ - cmDataSetCharPtr(p,(char*)vp,cnt); - p->tid = kVoidPtrDtId; - return p; -} - -cmData_t* cmDataSetCharPtr( cmData_t* p, char* vp, unsigned cnt ) -{ - _cmDataFreeArray(p); - p->tid = kCharPtrDtId; - p->u.cp = vp; - p->cnt = cnt; - return p; -} - -cmData_t* cmDataSetUCharPtr( cmData_t* p, unsigned char* vp, unsigned cnt ) -{ - _cmDataFreeArray(p); - p->tid = kUCharPtrDtId; - p->u.ucp = vp; - p->cnt = cnt; - return p; -} - -cmData_t* cmDataSetShortPtr( cmData_t* p, short* vp, unsigned cnt ) -{ - _cmDataFreeArray(p); - p->tid = kShortPtrDtId; - p->u.sp = vp; - p->cnt = cnt; - return p; -} - -cmData_t* cmDataSetUShortPtr( cmData_t* p, unsigned short* vp, unsigned cnt ) -{ - _cmDataFreeArray(p); - p->tid = kUShortPtrDtId; - p->u.usp = vp; - p->cnt = cnt; - return p; -} - -cmData_t* cmDataSetIntPtr( cmData_t* p, int* vp, unsigned cnt ) -{ - _cmDataFreeArray(p); - p->tid = kCharPtrDtId; - p->u.ip = vp; - p->cnt = cnt; - return p; -} - -cmData_t* cmDataSetUIntPtr( cmData_t* p, unsigned int* vp, unsigned cnt ) -{ - _cmDataFreeArray(p); - p->tid = kUIntPtrDtId; - p->u.uip = vp; - p->cnt = cnt; - return p; -} - -cmData_t* cmDataSetLongPtr( cmData_t* p, long* vp, unsigned cnt ) -{ - _cmDataFreeArray(p); - p->tid = kLongPtrDtId; - p->u.lp = vp; - p->cnt = cnt; - return p; -} - -cmData_t* cmDataSetULongPtr( cmData_t* p, unsigned long* vp, unsigned cnt ) -{ - _cmDataFreeArray(p); - p->tid = kULongPtrDtId; - p->u.ulp = vp; - p->cnt = cnt; - return p; -} - -cmData_t* cmDataSetFloatPtr( cmData_t* p, float* vp, unsigned cnt ) -{ - _cmDataFreeArray(p); - p->tid = kFloatPtrDtId; - p->u.fp = vp; - p->cnt = cnt; - return p; -} - -cmData_t* cmDataSetDoublePtr( cmData_t* p, double* vp, unsigned cnt ) -{ - _cmDataFreeArray(p); - p->tid = kDoublePtrDtId; - p->u.dp = vp; - p->cnt = cnt; - return p; -} - -// Set the value of an existing array based data object. -// Allocate the internal array and copy the array into it. -cmData_t* cmDataSetStrAlloc( cmData_t* p, const cmChar_t* s ) -{ - if( cmIsFlag(p->flags,kDynPtrDtFl) ) - cmMemResizeStr(p->u.z,s); else { - _cmDataFreeArray(p); - p->u.z = cmMemAllocStr(s); + // free the previous value ... + if((rc = _cmDataFreeData(d)) != kOkDtRC ) + return rc; + + // and assign the new value (without reallocating the array) + d->u.vp = vp; + + d->flags = cmEnaFlag(d->flags,kFreeValueDtFl,cmIsFlag(flags,kFreeValueDtFl)); + } - p->tid = kStrDtId; - p->flags = cmSetFlag(p->flags,kDynPtrDtFl); - return p; + + // we can't set this above because the string type relies + // on knowing the previous type of the object + d->cid = kArrayDtId; + d->tid = tid; + d->cnt = eleCnt; + + return rc; + } -cmData_t* cmDataSetConstStrAlloc( cmData_t* p, const cmChar_t* s ) -{ return cmDataSetStrAlloc(p,s); } +cmDtRC_t cmDataSetCharArray( cmData_t* d, char* v, unsigned eleCnt, unsigned flags ) +{ return cmDataSetArrayValue(d, kCharDtId, v, eleCnt, flags ); } +cmDtRC_t cmDataSetUCharArray( cmData_t* d, unsigned char* v, unsigned eleCnt, unsigned flags ) +{ return cmDataSetArrayValue(d, kUCharDtId, v, eleCnt, flags ); } +cmDtRC_t cmDataSetShortArray( cmData_t* d, short* v, unsigned eleCnt, unsigned flags ) +{ return cmDataSetArrayValue(d, kShortDtId, v, eleCnt, flags ); } +cmDtRC_t cmDataSetUShortArray( cmData_t* d, unsigned short* v, unsigned eleCnt, unsigned flags ) +{ return cmDataSetArrayValue(d, kUShortDtId, v, eleCnt, flags ); } +cmDtRC_t cmDataSetIntArray( cmData_t* d, int* v, unsigned eleCnt, unsigned flags ) +{ return cmDataSetArrayValue(d, kIntDtId, v, eleCnt, flags ); } +cmDtRC_t cmDataSetUIntArray( cmData_t* d, unsigned int* v, unsigned eleCnt, unsigned flags ) +{ return cmDataSetArrayValue(d, kUIntDtId, v, eleCnt, flags ); } +cmDtRC_t cmDataSetLongArray( cmData_t* d, long* v, unsigned eleCnt, unsigned flags ) +{ return cmDataSetArrayValue(d, kLongDtId, v, eleCnt, flags ); } +cmDtRC_t cmDataSetULongArray( cmData_t* d, unsigned long* v, unsigned eleCnt, unsigned flags ) +{ return cmDataSetArrayValue(d, kULongDtId, v, eleCnt, flags ); } +cmDtRC_t cmDataSetFloatArray( cmData_t* d, float* v, unsigned eleCnt, unsigned flags ) +{ return cmDataSetArrayValue(d, kFloatDtId, v, eleCnt, flags ); } +cmDtRC_t cmDataSetDoubleArray( cmData_t* d, double* v, unsigned eleCnt, unsigned flags ) +{ return cmDataSetArrayValue(d, kDoubleDtId, v, eleCnt, flags ); } +cmDtRC_t cmDataSetStrArray( cmData_t* d, cmChar_t** v, unsigned eleCnt, unsigned flags ) +{ return cmDataSetArrayValue(d, kStrDtId, v, eleCnt, flags ); } +cmDtRC_t cmDataSetConstStrArray(cmData_t* d,const cmChar_t** v,unsigned eleCnt, unsigned flags ) +{ return cmDataSetArrayValue(d, kStrDtId, (cmChar_t**)v, eleCnt, flags ); } -cmData_t* cmDataSetVoidAllocPtr( cmData_t* p, const void* vp, unsigned cnt ) -{ return cmDataSetCharAllocPtr(p,(char*)vp,cnt); } -cmData_t* cmDataSetCharAllocPtr( cmData_t* p, const char* vp, unsigned cnt ) +unsigned cmDataArrayEleCount( const cmData_t* d ) +{ return d->cid==kArrayDtId ? d->cnt : 0; } + + +cmDtRC_t cmDataCharArray( const cmData_t* d, char** v ) { - if( cmIsFlag(p->flags,kDynPtrDtFl) ) - p->u.cp = cmMemResize(char, p->u.cp, cnt ); - else - { - _cmDataFreeArray(p); - p->u.cp = cmMemAlloc(char, cnt ); - } - memcpy(p->u.cp,vp,sizeof(char)*cnt); - p->tid = kCharPtrDtId; - p->flags = cmSetFlag(p->flags,kDynPtrDtFl); - p->cnt = cnt; - return p; + if( d->cid != kArrayDtId ) + return _cmDtErrMsg(d,kInvalidContDtRC,"Cannot return an array base for a %s container.",cmDataContainerIdToLabel(d->cid)); + *v = (char*)d->u.vp; + return kOkDtRC; } -cmData_t* cmDataSetUCharAllocPtr( cmData_t* p, const unsigned char* vp, unsigned cnt ) +cmDtRC_t cmDataUCharArray( const cmData_t* d, unsigned char** v ) { - if( cmIsFlag(p->flags,kDynPtrDtFl) ) - p->u.ucp = cmMemResize(unsigned char, p->u.ucp, cnt ); - else - { - _cmDataFreeArray(p); - p->u.ucp = cmMemAlloc(unsigned char, cnt ); - } - memcpy(p->u.ucp,vp,sizeof(unsigned char)*cnt); - p->tid = kUCharPtrDtId; - p->flags = cmSetFlag(p->flags,kDynPtrDtFl); - p->cnt = cnt; - return p; + if( d->cid != kArrayDtId ) + return _cmDtErrMsg(d,kInvalidContDtRC,"Cannot return an array base for a %s container.",cmDataContainerIdToLabel(d->cid)); + *v = (unsigned char*)d->u.vp; + return kOkDtRC; } -cmData_t* cmDataSetShortAllocPtr( cmData_t* p, const short* vp, unsigned cnt ) +cmDtRC_t cmDataShortArray( const cmData_t* d, short** v ) { - if( cmIsFlag(p->flags,kDynPtrDtFl) ) - p->u.sp = cmMemResize(short, p->u.sp, cnt ); - else - { - _cmDataFreeArray(p); - p->u.sp = cmMemAlloc(short, cnt ); - } - memcpy(p->u.sp,vp,sizeof(short)*cnt); - p->tid = kShortPtrDtId; - p->flags = cmSetFlag(p->flags,kDynPtrDtFl); - p->cnt = cnt; - return p; + if( d->cid != kArrayDtId ) + return _cmDtErrMsg(d,kInvalidContDtRC,"Cannot return an array base for a %s container.",cmDataContainerIdToLabel(d->cid)); + *v = (short*)d->u.vp; + return kOkDtRC; } -cmData_t* cmDataSetUShortAllocPtr( cmData_t* p, const unsigned short* vp, unsigned cnt ) +cmDtRC_t cmDataUShortArray( const cmData_t* d, unsigned short** v ) { - if( cmIsFlag(p->flags,kDynPtrDtFl) ) - p->u.usp = cmMemResize(unsigned short, p->u.usp, cnt ); - else - { - _cmDataFreeArray(p); - p->u.usp = cmMemAlloc(unsigned short, cnt ); - } - memcpy(p->u.usp,vp,sizeof(unsigned short)*cnt); - p->tid = kUShortPtrDtId; - p->flags = cmSetFlag(p->flags,kDynPtrDtFl); - p->cnt = cnt; - return p; + if( d->cid != kArrayDtId ) + return _cmDtErrMsg(d,kInvalidContDtRC,"Cannot return an array base for a %s container.",cmDataContainerIdToLabel(d->cid)); + *v = (unsigned short*)d->u.vp; + return kOkDtRC; } -cmData_t* cmDataSetIntAllocPtr( cmData_t* p, const int* vp, unsigned cnt ) +cmDtRC_t cmDataIntArray( const cmData_t* d, int** v ) { - if( cmIsFlag(p->flags,kDynPtrDtFl) ) - p->u.ip = cmMemResize(int, p->u.ip, cnt ); - else - { - _cmDataFreeArray(p); - p->u.ip = cmMemAlloc(int, cnt ); - } - memcpy(p->u.ip,vp,sizeof(int)*cnt); - p->tid = kIntPtrDtId; - p->flags = cmSetFlag(p->flags,kDynPtrDtFl); - p->cnt = cnt; - return p; + if( d->cid != kArrayDtId ) + return _cmDtErrMsg(d,kInvalidContDtRC,"Cannot return an array base for a %s container.",cmDataContainerIdToLabel(d->cid)); + *v = (int*)d->u.vp; + return kOkDtRC; } -cmData_t* cmDataSetUIntAllocPtr( cmData_t* p, const unsigned int* vp, unsigned cnt ) +cmDtRC_t cmDataUIntArray( const cmData_t* d, unsigned int** v ) { - if( cmIsFlag(p->flags,kDynPtrDtFl) ) - p->u.uip = cmMemResize(unsigned int, p->u.uip, cnt ); - else - { - _cmDataFreeArray(p); - p->u.uip = cmMemAlloc(unsigned int, cnt ); - } - memcpy(p->u.uip,vp,sizeof(unsigned int)*cnt); - p->tid = kUIntPtrDtId; - p->flags = cmSetFlag(p->flags,kDynPtrDtFl); - p->cnt = cnt; - return p; + if( d->cid != kArrayDtId ) + return _cmDtErrMsg(d,kInvalidContDtRC,"Cannot return an array base for a %s container.",cmDataContainerIdToLabel(d->cid)); + *v = (unsigned int*)d->u.vp; + return kOkDtRC; } - -cmData_t* cmDataSetLongAllocPtr( cmData_t* p, const long* vp, unsigned cnt ) +cmDtRC_t cmDataLongArray( const cmData_t* d, long** v ) { - if( cmIsFlag(p->flags,kDynPtrDtFl) ) - p->u.lp = cmMemResize(long, p->u.lp, cnt ); - else - { - _cmDataFreeArray(p); - p->u.lp = cmMemAlloc(long, cnt ); - } - memcpy(p->u.lp,vp,sizeof(long)*cnt); - p->tid = kLongPtrDtId; - p->flags = cmSetFlag(p->flags,kDynPtrDtFl); - p->cnt = cnt; - return p; + if( d->cid != kArrayDtId ) + return _cmDtErrMsg(d,kInvalidContDtRC,"Cannot return an array base for a %s container.",cmDataContainerIdToLabel(d->cid)); + *v = (long*)d->u.vp; + return kOkDtRC; } - -cmData_t* cmDataSetULongAllocPtr( cmData_t* p, const unsigned long* vp, unsigned cnt ) +cmDtRC_t cmDataULongArray( const cmData_t* d, unsigned long** v ) { - if( cmIsFlag(p->flags,kDynPtrDtFl) ) - p->u.ulp = cmMemResize(unsigned long, p->u.ulp, cnt ); - else - { - _cmDataFreeArray(p); - p->u.ulp = cmMemAlloc(unsigned long, cnt ); - } - memcpy(p->u.ulp,vp,sizeof(unsigned long)*cnt); - p->tid = kULongPtrDtId; - p->flags = cmSetFlag(p->flags,kDynPtrDtFl); - p->cnt = cnt; - return p; + if( d->cid != kArrayDtId ) + return _cmDtErrMsg(d,kInvalidContDtRC,"Cannot return an array base for a %s container.",cmDataContainerIdToLabel(d->cid)); + *v = (unsigned long*)d->u.vp; + return kOkDtRC; } - -cmData_t* cmDataSetFloatAllocPtr( cmData_t* p, const float* vp, unsigned cnt ) +cmDtRC_t cmDataFloatArray( const cmData_t* d, float** v ) { - if( cmIsFlag(p->flags,kDynPtrDtFl) ) - p->u.fp = cmMemResize(float, p->u.fp, cnt ); - else - { - _cmDataFreeArray(p); - p->u.fp = cmMemAlloc(float, cnt ); - } - memcpy(p->u.fp,vp,sizeof(float)*cnt); - p->tid = kFloatPtrDtId; - p->flags = cmSetFlag(p->flags,kDynPtrDtFl); - p->cnt = cnt; - return p; + if( d->cid != kArrayDtId ) + return _cmDtErrMsg(d,kInvalidContDtRC,"Cannot return an array base for a %s container.",cmDataContainerIdToLabel(d->cid)); + *v = (float*)d->u.vp; + return kOkDtRC; } - -cmData_t* cmDataSetDoubleAllocPtr( cmData_t* p, const double* vp, unsigned cnt ) +cmDtRC_t cmDataDoubleArray( const cmData_t* d, double** v ) { - if( cmIsFlag(p->flags,kDynPtrDtFl) ) - p->u.dp = cmMemResize(double, p->u.dp, cnt ); - else - { - _cmDataFreeArray(p); - p->u.dp = cmMemAlloc(double, cnt ); - } - memcpy(p->u.dp,vp,sizeof(double)*cnt); - p->tid = kDoublePtrDtId; - p->flags = cmSetFlag(p->flags,kDynPtrDtFl); - p->cnt = cnt; - return p; + if( d->cid != kArrayDtId ) + return _cmDtErrMsg(d,kInvalidContDtRC,"Cannot return an array base for a %s container.",cmDataContainerIdToLabel(d->cid)); + *v = (double*)d->u.vp; + return kOkDtRC; } - - -// Dynamically allocate a data object and set it's value. -cmData_t* cmDataAllocNull( cmData_t* parent ) -{ return _cmDataAllocNode(parent,kNullDtId); } - -cmData_t* cmDataAllocChar( cmData_t* parent, char v ) +#ifdef NOT_DEF +cmDtRC_t cmDataStrArray( const cmData_t* d, cmChar_t*** v ) { - cmData_t* p = _cmDataAllocNode(parent,kCharDtId); - cmDataSetChar(p,v); - return p; } -cmData_t* cmDataAllocUChar( cmData_t* parent, unsigned char v ) +cmDtRC_t cmDataConstStrArray( const cmData_t* d, const cmChar_t*** v ) { - cmData_t* p = _cmDataAllocNode(parent,kUCharDtId); - cmDataSetUChar(p,v); - return p; -} - -cmData_t* cmDataAllocShort( cmData_t* parent, short v ) -{ - cmData_t* p = _cmDataAllocNode(parent,kShortDtId); - cmDataSetShort(p,v); - return p; -} - -cmData_t* cmDataAllocUShort( cmData_t* parent, unsigned short v ) -{ - cmData_t* p = _cmDataAllocNode(parent,kUShortDtId); - cmDataSetUShort(p,v); - return p; -} - -cmData_t* cmDataAllocInt( cmData_t* parent, int v ) -{ - cmData_t* p = _cmDataAllocNode(parent,kIntDtId); - cmDataSetInt(p,v); - return p; -} - -cmData_t* cmDataAllocUInt( cmData_t* parent, unsigned int v ) -{ - cmData_t* p = _cmDataAllocNode(parent,kUIntDtId); - cmDataSetUInt(p,v); - return p; -} - -cmData_t* cmDataAllocLong( cmData_t* parent, long v ) -{ - cmData_t* p = _cmDataAllocNode(parent,kLongDtId); - cmDataSetLong(p,v); - return p; -} - -cmData_t* cmDataAllocULong( cmData_t* parent, unsigned long v ) -{ - cmData_t* p = _cmDataAllocNode(parent,kULongDtId); - cmDataSetULong(p,v); - return p; -} - -cmData_t* cmDataAllocFloat( cmData_t* parent, float v ) -{ - cmData_t* p = _cmDataAllocNode(parent,kFloatDtId); - cmDataSetFloat(p,v); - return p; -} - -cmData_t* cmDataAllocDouble( cmData_t* parent, double v ) -{ - cmData_t* p = _cmDataAllocNode(parent,kDoubleDtId); - cmDataSetDouble(p,v); - return p; -} - - -// Dynamically allocate a data object and set its array value to an external -// array. The data is not copied. -cmData_t* cmDataAllocStr( cmData_t* parent, cmChar_t* str ) -{ - cmData_t* p = _cmDataAllocNode(parent,kStrDtId); - cmDataSetStr(p,str); - return p; -} - -cmData_t* cmDataAllocConstStr( cmData_t* parent, const cmChar_t* str ) -{ - cmData_t* p = _cmDataAllocNode(parent,kConstStrDtId); - cmDataSetConstStr(p,str); - return p; -} - -cmData_t* cmDataAllocCharPtr( cmData_t* parent, char* v, unsigned cnt ) -{ - cmData_t* p = _cmDataAllocNode(parent,kCharPtrDtId); - cmDataSetCharPtr(p,(char*)v,cnt); - return p; -} - -cmData_t* cmDataAllocUCharPtr( cmData_t* parent, unsigned char* v, unsigned cnt ) -{ - cmData_t* p = _cmDataAllocNode(parent,kUCharPtrDtId); - cmDataSetUCharPtr(p,(unsigned char*)v,cnt); - return p; -} - -cmData_t* cmDataAllocShortPtr( cmData_t* parent, short* v, unsigned cnt ) -{ - cmData_t* p = _cmDataAllocNode(parent,kShortPtrDtId); - cmDataSetShortPtr(p,(short*)v,cnt); - return p; -} - -cmData_t* cmDataAllocUShortPtr( cmData_t* parent, unsigned short* v, unsigned cnt ) -{ - cmData_t* p = _cmDataAllocNode(parent,kUShortPtrDtId); - cmDataSetUShortPtr(p,(unsigned short*)v,cnt); - return p; -} - -cmData_t* cmDataAllocIntPtr( cmData_t* parent, int* v, unsigned cnt ) -{ - cmData_t* p = _cmDataAllocNode(parent,kIntPtrDtId); - cmDataSetIntPtr(p,(int*)v,cnt); - return p; -} - -cmData_t* cmDataAllocUIntPtr( cmData_t* parent, unsigned int* v, unsigned cnt ) -{ - cmData_t* p = _cmDataAllocNode(parent,kUIntPtrDtId); - cmDataSetUIntPtr(p,(unsigned int*)v,cnt); - return p; -} - -cmData_t* cmDataAllocLongPtr( cmData_t* parent, long* v, unsigned cnt ) -{ - cmData_t* p = _cmDataAllocNode(parent,kLongPtrDtId); - cmDataSetLongPtr(p,(long*)v,cnt); - return p; -} - -cmData_t* cmDataAllocULongPtr( cmData_t* parent, unsigned long* v, unsigned cnt ) -{ - cmData_t* p = _cmDataAllocNode(parent,kULongPtrDtId); - cmDataSetULongPtr(p,(unsigned long*)v,cnt); - return p; -} - -cmData_t* cmDataAllocFloatPtr( cmData_t* parent, float* v, unsigned cnt ) -{ - cmData_t* p = _cmDataAllocNode(parent,kFloatPtrDtId); - cmDataSetFloatPtr(p,(float*)v,cnt); - return p; -} - -cmData_t* cmDataAllocDoublePtr( cmData_t* parent, double* v, unsigned cnt ) -{ - cmData_t* p = _cmDataAllocNode(parent,kDoublePtrDtId); - cmDataSetDoublePtr(p,(double*)v,cnt); - return p; -} - -cmData_t* cmDataAllocVoidPtr( cmData_t* parent, void* v, unsigned cnt ) -{ - cmData_t* p = _cmDataAllocNode(parent,kVoidPtrDtId); - cmDataSetCharPtr(p,(char*)v,cnt); - p->tid = kVoidPtrDtId; - return p; } +#endif -// Dynamically allocate a data object and its array value. -// v[cnt] is copied into the allocated array. -cmData_t* cmDataStrAlloc( cmData_t* parent, cmChar_t* str ) -{ - cmData_t* p = _cmDataAllocNode(parent,kStrDtId); - cmDataSetStrAlloc(p,str); - return p; -} +//---------------------------------------------------------------------------- +// Structure related functions +// -cmData_t* cmDataConstStrAlloc( cmData_t* parent, const cmChar_t* str ) -{ - cmData_t* p = _cmDataAllocNode(parent,kConstStrDtId); - cmDataSetConstStrAlloc(p,str); - return p; -} - -cmData_t* cmDataCharAllocPtr( cmData_t* parent, const char* v, unsigned cnt ) -{ - cmData_t* p = _cmDataAllocNode(parent,kCharPtrDtId); - cmDataSetCharAllocPtr(p, v, cnt ); - return p; -} - -cmData_t* cmDataUCharAllocPtr( cmData_t* parent, const unsigned char* v, unsigned cnt ) -{ - cmData_t* p = _cmDataAllocNode(parent,kUCharPtrDtId); - cmDataSetUCharAllocPtr(p, v, cnt ); - return p; -} - -cmData_t* cmDataShortAllocPtr( cmData_t* parent, const short* v, unsigned cnt ) -{ - cmData_t* p = _cmDataAllocNode(parent,kShortPtrDtId); - cmDataSetShortAllocPtr(p, v, cnt ); - return p; -} - -cmData_t* cmDataUShortAllocPtr( cmData_t* parent, const unsigned short* v, unsigned cnt ) -{ - cmData_t* p = _cmDataAllocNode(parent,kUShortPtrDtId); - cmDataSetUShortAllocPtr(p, v, cnt ); - return p; -} - -cmData_t* cmDataIntAllocPtr( cmData_t* parent, const int* v, unsigned cnt ) -{ - cmData_t* p = _cmDataAllocNode(parent,kIntPtrDtId); - cmDataSetIntAllocPtr(p, v, cnt ); - return p; -} - -cmData_t* cmDataUIntAllocPtr( cmData_t* parent, const unsigned int* v, unsigned cnt ) -{ - cmData_t* p = _cmDataAllocNode(parent,kUIntPtrDtId); - cmDataSetUIntAllocPtr(p, v, cnt ); - return p; -} - -cmData_t* cmDataLongAllocPtr( cmData_t* parent, const long* v, unsigned cnt ) -{ - cmData_t* p = _cmDataAllocNode(parent,kLongPtrDtId); - cmDataSetLongAllocPtr(p, v, cnt ); - return p; -} - -cmData_t* cmDataULongAllocPtr( cmData_t* parent, const unsigned long* v, unsigned cnt ) -{ - cmData_t* p = _cmDataAllocNode(parent,kULongPtrDtId); - cmDataSetULongAllocPtr(p, v, cnt ); - return p; -} - -cmData_t* cmDataFloatAllocPtr( cmData_t* parent, const float* v, unsigned cnt ) -{ - cmData_t* p = _cmDataAllocNode(parent,kFloatPtrDtId); - cmDataSetFloatAllocPtr(p, v, cnt ); - return p; -} - -cmData_t* cmDataDoubleAllocPtr( cmData_t* parent, const double* v, unsigned cnt ) -{ - cmData_t* p = _cmDataAllocNode(parent,kDoublePtrDtId); - cmDataSetDoubleAllocPtr(p, v, cnt ); - return p; -} - - -cmData_t* cmDataVoidAllocPtr( cmData_t* parent, const void* v, unsigned cnt ) -{ - cmData_t* p = _cmDataAllocNode(parent,kVoidPtrDtId); - cmDataSetCharAllocPtr(p, (const char*)v, cnt ); - p->tid = kVoidPtrDtId; - return p; -} void cmDataFree( cmData_t* p ) { @@ -1149,58 +1057,56 @@ void cmDataUnlinkAndFree( cmData_t* p ) cmDataFree(p); } -cmData_t* _cmDataDupl( const cmData_t* p, cmData_t* parent ) +cmDtRC_t _cmDataDupl( const cmData_t* d, cmData_t* parent, cmData_t** ref ) { + cmDtRC_t rc = kOkDtRC; cmData_t* rp = NULL; - switch( p->tid ) + *ref = NULL; + + switch( d->cid ) { - case kNullDtId: rp = cmDataAllocNull(parent); break; - case kUCharDtId: rp = cmDataAllocUChar(parent,p->u.uc); break; - case kCharDtId: rp = cmDataAllocChar(parent,p->u.c); break; - case kUShortDtId: rp = cmDataAllocShort(parent,p->u.us); break; - case kShortDtId: rp = cmDataAllocUShort(parent,p->u.s); break; - case kUIntDtId: rp = cmDataAllocUInt(parent,p->u.i); break; - case kIntDtId: rp = cmDataAllocInt(parent,p->u.ui); break; - case kULongDtId: rp = cmDataAllocULong(parent,p->u.ul); break; - case kLongDtId: rp = cmDataAllocLong(parent,p->u.l); break; - case kFloatDtId: rp = cmDataAllocFloat(parent,p->u.f); break; - case kDoubleDtId: rp = cmDataAllocDouble(parent,p->u.d); break; + case kScalarDtId: + if( d->tid == kBlobDtId || d->tid == kStrDtId ) + rc = cmDataNewScalar(parent, d->tid, d->flags, d->u.vp, d->cnt, &rp ); + else + rc = cmDataNewScalar(parent, d->tid, d->flags, d->u.vp, 0, &rp ); + break; - case kStrDtId: rp = cmDataStrAlloc(parent,p->u.z); break; - case kConstStrDtId: rp = cmDataConstStrAlloc(parent,p->u.cz); break; - case kUCharPtrDtId: rp = cmDataUCharAllocPtr(parent,p->u.ucp,p->cnt); break; - case kCharPtrDtId: rp = cmDataCharAllocPtr(parent,p->u.cp,p->cnt); break; - case kUShortPtrDtId: rp = cmDataUShortAllocPtr(parent,p->u.usp,p->cnt); break; - case kShortPtrDtId: rp = cmDataShortAllocPtr(parent,p->u.sp,p->cnt); break; - case kUIntPtrDtId: rp = cmDataUIntAllocPtr(parent,p->u.uip,p->cnt); break; - case kIntPtrDtId: rp = cmDataIntAllocPtr(parent,p->u.ip,p->cnt); break; - case kULongPtrDtId: rp = cmDataULongAllocPtr(parent,p->u.ulp,p->cnt); break; - case kLongPtrDtId: rp = cmDataLongAllocPtr(parent,p->u.lp,p->cnt); break; - case kFloatPtrDtId: rp = cmDataFloatAllocPtr(parent,p->u.fp,p->cnt); break; - case kDoublePtrDtId: rp = cmDataDoubleAllocPtr(parent,p->u.dp,p->cnt); break; - case kVoidPtrDtId: rp = cmDataVoidAllocPtr(parent,p->u.vp,p->cnt); break; + case kArrayDtId: + rc = cmDataNewArray(parent, d->tid, d->u.vp, d->cnt, d->flags, &rp ); + break; - case kListDtId: - case kPairDtId: + case kListDtId: + case kPairDtId: case kRecordDtId: { - rp = _cmDataAllocNode(parent,p->tid); - cmData_t* cp = p->u.child; + rp = _cmDataNew(parent,d->cid,d->tid); + const cmData_t* cp = d->u.child; for(; cp!=NULL; cp=cp->sibling) - cmDataAppendChild(rp,_cmDataDupl(cp,rp)); + { + cmData_t* ncp = NULL; + // duplicate the child (ncp) and append it to the parent (rp) + if((rc = _cmDataDupl(cp,rp,&ncp)) == kOkDtRC ) + cmDataAppendChild(rp,ncp); + } } + break; default: assert(0); + break; } - return rp; + if( rp != NULL ) + *ref = rp; + + return rc; } -cmData_t* cmDataDupl( const cmData_t* p ) -{ return _cmDataDupl(p,NULL); } +cmRC_t cmDataDupl( const cmData_t* p, cmData_t** ref ) +{ return _cmDataDupl(p,NULL,ref); } cmData_t* cmDataReplace( cmData_t* dst, cmData_t* src ) { @@ -1240,6 +1146,7 @@ cmData_t* cmDataReplace( cmData_t* dst, cmData_t* src ) } pp = cp; } + return src; } @@ -1290,7 +1197,7 @@ cmData_t* cmDataPrependChild(cmData_t* parent, cmData_t* p ) cmData_t* cmDataAppendChild( cmData_t* parent, cmData_t* p ) { assert( cmDataIsStruct(parent) ); - assert( parent->tid != kRecordDtId || (parent->tid == kRecordDtId && p->tid==kPairDtId)); + assert( parent->cid != kRecordDtId || (parent->cid == kRecordDtId && p->cid==kPairDtId)); cmDataUnlink(p); @@ -1348,14 +1255,14 @@ cmData_t* cmDataInsertChild( cmData_t* parent, unsigned index, cmData_t* p ) } + //---------------------------------------------------------------------------- bool _cmDataPairIsValid( const cmData_t* p ) { - assert( p->tid == kPairDtId ); + assert( p->cid == kPairDtId && p->tid==kStructDtId ); - const cmData_t* cp = p->u.child; - bool fl = cp->u.child == NULL || cp->u.child->sibling == NULL || cp->u.child->sibling->sibling!=NULL; + bool fl = p->u.child == NULL || p->u.child->sibling == NULL || p->u.child->sibling->sibling!=NULL; return !fl; } @@ -1378,7 +1285,7 @@ const cmChar_t* cmDataPairKeyLabel( cmData_t* p ) { assert( _cmDataPairIsValid(p) ); const cmChar_t* label = NULL; - cmDataGetConstStr(p->u.child,&label); + cmDataConstStr(p->u.child,&label); return label; } @@ -1415,7 +1322,7 @@ cmData_t* cmDataPairSetKeyId( cmData_t* p, unsigned id ) cmData_t* cmDataPairSetKeyLabel( cmData_t* p, const cmChar_t* label ) { assert( _cmDataPairIsValid(p) ); - cmDataSetConstStrAlloc(p->u.child,label); + cmDataSetConstStr(p->u.child,kNoFlagsDtFl,label); return p; } @@ -1423,7 +1330,8 @@ cmData_t* cmDataPairSetKeyLabel( cmData_t* p, const cmChar_t* label ) cmData_t* cmDataMakePair( cmData_t* parent, cmData_t* p, cmData_t* key, cmData_t* value ) { _cmDataFree(p); - p->tid = kPairDtId; + p->tid = kStructDtId; + p->cid = kPairDtId; p->parent = parent; p->flags = 0; p->u.child = NULL; @@ -1435,9 +1343,14 @@ cmData_t* cmDataMakePair( cmData_t* parent, cmData_t* p, cmData_t* key, cmData_t // Dynamically allocate a pair node cmData_t* cmDataAllocPair( cmData_t* parent, const cmData_t* key, const cmData_t* value ) { - cmData_t* p = _cmDataAllocNode(parent,kPairDtId); - cmData_t* kp = cmDataDupl(key); - cmData_t* vp = cmDataDupl(value); + cmData_t* p = _cmDataNew(parent,kPairDtId,kStructDtId); + cmData_t* kp = NULL; + cmData_t* vp = NULL; + + // BUG BUG BUG - must check return value of cmDataDupl() + cmDataDupl(key,&kp); + cmDataDupl(value,&vp); + cmDataPrependChild(p,vp); cmDataPrependChild(p,kp); return p; @@ -1445,19 +1358,31 @@ cmData_t* cmDataAllocPair( cmData_t* parent, const cmData_t* key, const cmData_ cmData_t* cmDataAllocPairId(cmData_t* parent, unsigned keyId, cmData_t* value ) { - cmData_t* p = _cmDataAllocNode(parent,kPairDtId); - cmDataAllocUInt(p,keyId); + cmData_t* p = _cmDataNew(parent,kPairDtId,kStructDtId); + cmDataNewUInt(p,kNoFlagsDtFl,keyId,NULL); cmDataAppendChild(p,value); return p; } cmData_t* cmDataAllocPairLabel( cmData_t* parent, const cmChar_t *label, cmData_t* value ) { - cmData_t* p = _cmDataAllocNode(parent,kPairDtId); - cmDataConstStrAlloc(p,label); + cmData_t* p = _cmDataNew(parent,kPairDtId,kStructDtId); + + // BUG BUG BUG - should check return value + cmDataNewConstStr(p,kNoFlagsDtFl,label,NULL); cmDataAppendChild(p,value); return p; } + +cmData_t* cmDataAllocPairLabelN(cmData_t* parent, const cmChar_t* label, unsigned charCnt, cmData_t* value) +{ + cmData_t* p = _cmDataNew(parent,kPairDtId,kStructDtId); + // BUG BUG BUG - should check return value + cmDataNewConstStrN(p,kNoFlagsDtFl,label,charCnt,NULL); + cmDataAppendChild(p,value); + return p; +} + //---------------------------------------------------------------------------- @@ -1478,117 +1403,72 @@ cmData_t* cmDataListMake( cmData_t* parent, cmData_t* p ) } cmData_t* cmDataListAlloc( cmData_t* parent) -{ return _cmDataAllocNode(parent,kListDtId); } +{ return _cmDataNew(parent,kListDtId,kStructDtId); } cmDtRC_t _cmDataParseArgV( cmData_t* parent, va_list vl, cmData_t** vpp ) { - cmDtRC_t rc = kOkDtRC; - cmData_t* vp = NULL; - unsigned tid = va_arg(vl,unsigned); + cmDtRC_t rc = kOkDtRC; + cmData_t* vp = NULL; + cmDataContainerId_t cid = va_arg(vl,unsigned); + cmDataTypeId_t tid = va_arg(vl,unsigned); - switch(tid) + switch(cid) { - case kInvalidDtId: rc = kEolDtRC; break; - case kNullDtId: vp = cmDataAllocNull(parent); break; - case kUCharDtId: vp = cmDataAllocUChar( parent,va_arg(vl,int)); break; - case kCharDtId: vp = cmDataAllocChar( parent,va_arg(vl,int)); break; - case kUShortDtId: vp = cmDataAllocUShort( parent,va_arg(vl,int)); break; - case kShortDtId: vp = cmDataAllocShort( parent,va_arg(vl,int)); break; - case kUIntDtId: vp = cmDataAllocUInt( parent,va_arg(vl,unsigned int)); break; - case kIntDtId: vp = cmDataAllocInt( parent,va_arg(vl,int)); break; - case kULongDtId: vp = cmDataAllocULong( parent,va_arg(vl,unsigned long)); break; - case kLongDtId: vp = cmDataAllocLong( parent,va_arg(vl,long)); break; - case kFloatDtId: vp = cmDataAllocFloat( parent,va_arg(vl,double)); break; - case kDoubleDtId: vp = cmDataAllocDouble( parent,va_arg(vl,double)); break; - - case kStrDtId: vp = cmDataStrAlloc( parent,va_arg(vl,cmChar_t*)); break; - case kConstStrDtId: vp = cmDataConstStrAlloc( parent,va_arg(vl,const cmChar_t*)); break; - - case kUCharPtrDtId: + case kInvalidCntDtId: rc = kEolDtRC; break; + + case kScalarDtId: + switch(tid) { - unsigned char* p = va_arg(vl,unsigned char*); - vp = cmDataUCharAllocPtr(parent, p, va_arg(vl,unsigned)); + case kNullDtId: rc = cmDataNewNull( parent,kNoFlagsDtFl,&vp); break; + case kUCharDtId: rc = cmDataNewUChar( parent,kNoFlagsDtFl,va_arg(vl,int),&vp); break; + case kCharDtId: rc = cmDataNewChar( parent,kNoFlagsDtFl,va_arg(vl,int),&vp); break; + case kUShortDtId: rc = cmDataNewUShort( parent,kNoFlagsDtFl,va_arg(vl,int),&vp); break; + case kShortDtId: rc = cmDataNewShort( parent,kNoFlagsDtFl,va_arg(vl,int),&vp); break; + case kUIntDtId: rc = cmDataNewUInt( parent,kNoFlagsDtFl,va_arg(vl,unsigned int),&vp); break; + case kIntDtId: rc = cmDataNewInt( parent,kNoFlagsDtFl,va_arg(vl,int),&vp); break; + case kULongDtId: rc = cmDataNewULong( parent,kNoFlagsDtFl,va_arg(vl,unsigned long),&vp); break; + case kLongDtId: rc = cmDataNewLong( parent,kNoFlagsDtFl,va_arg(vl,long),&vp); break; + case kFloatDtId: rc = cmDataNewFloat( parent,kNoFlagsDtFl,va_arg(vl,double),&vp); break; + case kDoubleDtId: rc = cmDataNewDouble( parent,kNoFlagsDtFl,va_arg(vl,double),&vp); break; + case kStrDtId: rc = cmDataNewStr( parent,kNoFlagsDtFl,va_arg(vl,cmChar_t*),&vp); break; + default: + // BUG BUG BUG - signal an error here + assert(0); + break; } break; - case kCharPtrDtId: + case kArrayDtId: + switch(tid) { - char* p = va_arg(vl,char*); - vp = cmDataCharAllocPtr(parent, p, va_arg(vl,unsigned)); - } - break; - - case kUShortPtrDtId: - { - unsigned short* p = va_arg(vl,unsigned short*); - vp = cmDataUShortAllocPtr(parent, p, va_arg(vl,unsigned)); - } - break; - - case kShortPtrDtId: - { - short* p = va_arg(vl,short*); - vp = cmDataShortAllocPtr(parent, p, va_arg(vl,unsigned)); - } - break; - - case kUIntPtrDtId: - { - unsigned int* p = va_arg(vl,unsigned int*); - vp = cmDataUIntAllocPtr(parent, p, va_arg(vl,unsigned)); - } - break; - - case kIntPtrDtId: - { - int * p = va_arg(vl,int*); - vp = cmDataIntAllocPtr(parent, p, va_arg(vl,unsigned)); - } - break; - - case kULongPtrDtId: - { - unsigned long* p = va_arg(vl,unsigned long*); - vp = cmDataULongAllocPtr(parent, p, va_arg(vl,unsigned)); - } - break; - - case kLongPtrDtId: - { - long* p = va_arg(vl,long*); - vp = cmDataLongAllocPtr(parent, p, va_arg(vl,unsigned)); - } - break; - - case kFloatPtrDtId: - { - float* p = va_arg(vl,float*); - vp = cmDataFloatAllocPtr(parent, p, va_arg(vl,unsigned)); - } - break; - - case kDoublePtrDtId: - { - double* p = va_arg(vl,double*); - vp = cmDataDoubleAllocPtr(parent,p, va_arg(vl,unsigned)); - } - break; - - case kVoidPtrDtId: - { - void* p = va_arg(vl,void*); - vp = cmDataVoidAllocPtr(parent, p, va_arg(vl,unsigned)); + case kUCharDtId: rc = cmDataNewUCharArray( parent,va_arg(vl,unsigned char*), va_arg(vl,unsigned),kNoFlagsDtFl,&vp); break; + case kCharDtId: rc = cmDataNewCharArray( parent,va_arg(vl,char*), va_arg(vl,unsigned),kNoFlagsDtFl,&vp); break; + case kUShortDtId: rc = cmDataNewUShortArray( parent,va_arg(vl,unsigned short*),va_arg(vl,unsigned),kNoFlagsDtFl,&vp); break; + case kShortDtId: rc = cmDataNewShortArray( parent,va_arg(vl,short*), va_arg(vl,unsigned),kNoFlagsDtFl,&vp); break; + case kUIntDtId: rc = cmDataNewUIntArray( parent,va_arg(vl,unsigned int*), va_arg(vl,unsigned),kNoFlagsDtFl,&vp); break; + case kIntDtId: rc = cmDataNewIntArray( parent,va_arg(vl,int*), va_arg(vl,unsigned),kNoFlagsDtFl,&vp); break; + case kULongDtId: rc = cmDataNewULongArray( parent,va_arg(vl,unsigned long*), va_arg(vl,unsigned),kNoFlagsDtFl,&vp); break; + case kLongDtId: rc = cmDataNewLongArray( parent,va_arg(vl,long*), va_arg(vl,unsigned),kNoFlagsDtFl,&vp); break; + case kFloatDtId: rc = cmDataNewFloatArray( parent,va_arg(vl,float*), va_arg(vl,unsigned),kNoFlagsDtFl,&vp); break; + case kDoubleDtId: rc = cmDataNewDoubleArray( parent,va_arg(vl,double*), va_arg(vl,unsigned),kNoFlagsDtFl,&vp); break; + case kStrDtId: rc = cmDataNewStrArray( parent,va_arg(vl,cmChar_t**), va_arg(vl,unsigned),kNoFlagsDtFl,&vp); break; + default: + // BUG BUG BUG - signal an error here + + assert(0); + break; } break; case kListDtId: case kPairDtId: case kRecordDtId: - vp = _cmDataAllocNode(parent,tid); + vp = _cmDataNew(parent,cid,kStructDtId); break; default: - _cmDataSetError(kVarArgErrDtRC); + // BUG BUG BUG - signal an error here + assert(0); break; } @@ -1597,49 +1477,62 @@ cmDtRC_t _cmDataParseArgV( cmData_t* parent, va_list vl, cmData_t** vpp ) return rc; } -cmData_t* _cmDataListParseV(cmData_t* parent, va_list vl ) +cmDtRC_t _cmDataListParseV(cmData_t* parent, va_list vl ) { - cmData_t* p = NULL; + cmDtRC_t rc = kOkDtRC; bool contFl = true; while( contFl ) { cmData_t* vp; - cmDtRC_t rc = _cmDataParseArgV(parent, vl, &vp); + + rc = _cmDataParseArgV(parent, vl, &vp); if(rc != kOkDtRC || cmDataAppendChild(parent,vp)==NULL ) contFl = false; } - return p; + + return rc; } -cmData_t* cmDataListAllocV(cmData_t* parent, va_list vl ) +cmRC_t cmDataListAllocV(cmData_t* parent, cmData_t** ref, va_list vl ) { cmData_t* p = cmDataListAlloc(parent); - _cmDataListParseV(p, vl ); - return p; + + cmRC_t rc; + + if((rc = _cmDataListParseV(p, vl )) != kOkDtRC ) + { + cmDataUnlinkAndFree(p); + return rc; + } + + if( ref != NULL ) + *ref = p; + + return rc; } -cmData_t* cmDataListAllocA(cmData_t* parent, ... ) +cmRC_t cmDataListAllocA(cmData_t* parent, cmData_t** ref, ... ) { va_list vl; - va_start(vl,parent); - cmData_t* p = cmDataListAllocV(parent,vl); + va_start(vl,ref); + cmRC_t rc = cmDataListAllocV(parent,ref,vl); va_end(vl); - return p; + return rc; } cmData_t* cmDataListAppendEle( cmData_t* p, cmData_t* ele ) { - assert(p->tid == kListDtId); + assert(p->cid == kListDtId && p->tid==kStructDtId); return cmDataAppendChild(p,ele); } cmData_t* cmDataListAppendEleN(cmData_t* p, cmData_t* ele[], unsigned n ) { - assert(p->tid == kListDtId); + assert(p->cid == kListDtId && p->tid==kStructDtId); cmData_t* rp = NULL; unsigned i; @@ -1654,8 +1547,9 @@ cmData_t* cmDataListAppendEleN(cmData_t* p, cmData_t* ele[], unsigned n ) cmDtRC_t cmDataListAppendV( cmData_t* p, va_list vl ) { - if( _cmDataListParseV(p, vl ) == NULL ) - return _cmDataErrNo; + cmDtRC_t rc; + if((rc = _cmDataListParseV(p, vl )) != kOkDtRC ) + return rc; return kOkDtRC; } @@ -1684,42 +1578,42 @@ cmData_t* cmDataListInsertEleN(cmData_t* p, unsigned index, cmData_t* ele[], uns //---------------------------------------------------------------------------- unsigned cmDataRecdCount( const cmData_t* p ) { - assert( p->tid == kRecordDtId ); + assert( p->cid == kRecordDtId && p->tid==kStructDtId ); return cmDataChildCount(p); } cmData_t* cmDataRecdEle( cmData_t* p, unsigned index ) { - assert( p->tid == kRecordDtId ); + assert( p->cid == kRecordDtId && p->tid==kStructDtId ); cmData_t* cp = cmDataChild(p,index); - assert( p->tid == kPairDtId ); + assert( p->cid == kPairDtId ); return cp; } cmData_t* cmDataRecdValueFromIndex( cmData_t* p, unsigned index ) { - assert( p->tid == kRecordDtId ); + assert( p->cid == kRecordDtId && p->tid==kStructDtId ); cmData_t* cp = cmDataChild(p,index); - assert( p->tid == kPairDtId ); + assert( p->cid == kPairDtId && p->tid==kStructDtId ); return cmDataPairValue(cp); } cmData_t* cmDataRecdValueFromId( cmData_t* p, unsigned id ) { - assert( p->tid == kRecordDtId ); + assert( p->cid == kRecordDtId || p->tid==kStructDtId ); cmData_t* cp = p->u.child; for(; cp!=NULL; cp=cp->sibling) if( cmDataPairKeyId(cp) == id ) break; - assert( cp!=NULL && cp->tid==kPairDtId ); + assert( cp!=NULL && cp->cid==kPairDtId && cp->tid==kStructDtId); return cmDataPairValue(cp); } cmData_t* cmDataRecdValueFromLabel( cmData_t* p, const cmChar_t* label ) { - assert( p->tid == kRecordDtId ); + assert( p->cid == kRecordDtId && p->tid==kStructDtId); cmData_t* cp = p->u.child; for(; cp!=NULL; cp=cp->sibling) { @@ -1728,16 +1622,16 @@ cmData_t* cmDataRecdValueFromLabel( cmData_t* p, const cmChar_t* label if( lp!=NULL && strcmp(lp,label)==0 ) break; } - assert( cp!=NULL && cp->tid==kPairDtId ); + assert( cp!=NULL && cp->cid==kPairDtId && cp->tid==kStructDtId); return cmDataPairValue(cp); } cmData_t* cmDataRecdKey( cmData_t* p, unsigned index ) { - assert( p->tid == kRecordDtId ); + assert( p->cid == kRecordDtId && p->tid==kStructDtId ); cmData_t* cp = cmDataChild(p,index); - assert( p->tid == kPairDtId ); + assert( cp->cid == kPairDtId && cp->tid==kStructDtId); return cmDataPairKey(cp); } @@ -1753,11 +1647,12 @@ const cmChar_t* cmDataRecdKeyLabel( cmData_t* p, unsigned index ) { cmData_t* kp = cmDataRecdKey(p,index); const cmChar_t* label = NULL; - cmDataGetConstStr(kp,&label); + // BUG BUG BUG - test return value + cmDataConstStr(kp,&label); return label; } -cmData_t* cmRecdMake( cmData_t* parent, cmData_t* p ) +cmData_t* cmDataRecdMake( cmData_t* parent, cmData_t* p ) { _cmDataFree(p); p->parent = parent; @@ -1767,12 +1662,12 @@ cmData_t* cmRecdMake( cmData_t* parent, cmData_t* p ) return p; } -cmData_t* cmRecdAlloc(cmData_t* parent) -{ return _cmDataAllocNode(parent,kRecordDtId); } +cmData_t* cmDataRecdAlloc(cmData_t* parent) +{ return _cmDataNew(parent,kRecordDtId,kStructDtId); } -cmData_t* cmRecdAppendPair( cmData_t* p, cmData_t* pair ) +cmData_t* cmDataRecdAppendPair( cmData_t* p, cmData_t* pair ) { - assert( p!=NULL && p->tid==kRecordDtId); + assert( p!=NULL && p->cid==kRecordDtId && p->tid==kStructDtId); cmDataAppendChild(p,pair); return p; } @@ -1780,7 +1675,7 @@ cmData_t* cmRecdAppendPair( cmData_t* p, cmData_t* pair ) cmDtRC_t _cmDataRecdParseInputV(cmData_t* parent, unsigned idFl, va_list vl ) { - assert( parent != NULL && parent->tid == kRecordDtId ); + assert( parent != NULL && parent->cid == kRecordDtId && parent->tid == kStructDtId ); bool contFl = true; cmDtRC_t rc = kOkDtRC; @@ -1798,7 +1693,7 @@ cmDtRC_t _cmDataRecdParseInputV(cmData_t* parent, unsigned idFl, va_list vl ) label = va_arg(vl,const char*); // text field label identifier // validate the field identifier - if( (idFl && id==kInvalidDtId) || (!idFl && label==NULL) ) + if( (idFl && id==cmInvalidId) || (!idFl && label==NULL) ) break; // parse the field data @@ -1820,7 +1715,7 @@ cmDtRC_t _cmDataRecdParseInputV(cmData_t* parent, unsigned idFl, va_list vl ) cmData_t* cmDataRecdAllocLabelV( cmData_t* parent, va_list vl ) { - cmData_t* p = cmRecdAlloc(parent); + cmData_t* p = cmDataRecdAlloc(parent); cmDtRC_t rc = _cmDataRecdParseInputV(p, false, vl ); if( rc != kOkDtRC ) { @@ -1841,7 +1736,7 @@ cmData_t* cmDataRecdAllocLabelA( cmData_t* parent, ... ) cmData_t* cmDataRecdAllocIdV( cmData_t* parent, va_list vl ) { - cmData_t* p = cmRecdAlloc(parent); + cmData_t* p = cmDataRecdAlloc(parent); cmDtRC_t rc = _cmDataRecdParseInputV(p, true, vl ); if( rc != kOkDtRC ) { @@ -1860,6 +1755,8 @@ cmData_t* cmDataRecdAllocIdA( cmData_t* parent, ... ) return p; } +#ifdef NOT_DEF + cmDtRC_t _cmDataRecdParseV(cmData_t* p, bool idFl, cmErr_t* err, unsigned errRC, va_list vl ) { bool contFl = true; @@ -1867,8 +1764,8 @@ cmDtRC_t _cmDataRecdParseV(cmData_t* p, bool idFl, cmErr_t* err, unsigned errRC, while( contFl ) { - unsigned id; - const char* label; + unsigned id = cmInvalidId; + const char* label = NULL; // parse the field idenfier if( idFl ) @@ -1877,14 +1774,15 @@ cmDtRC_t _cmDataRecdParseV(cmData_t* p, bool idFl, cmErr_t* err, unsigned errRC, label = va_arg(vl,const char*); // text field label identifier // validate the field identifier - if( (idFl && id==kInvalidDtId) || (!idFl && label==NULL) ) + if( (idFl && id==cmInvalidId) || (!idFl && label==NULL) ) break; - cmDataFmtId_t typeId = va_arg(vl,unsigned); - void* v = va_arg(vl,void*); - cmData_t* np = NULL; - bool optFl = cmIsFlag(typeId,kOptArgDtFl); - cmDtRC_t rc0 = kOkDtRC; + cmDataContainerId_t cid = va_arg(vl,unsigned); + cmDataTypeId_t typeId = va_arg(vl,unsigned); + void* v = va_arg(vl,void*); + cmData_t* np = NULL; + bool optFl = cmIsFlag(typeId,kOptArgDtFl); + cmDtRC_t rc0 = kOkDtRC; typeId = cmClrFlag(typeId,kOptArgDtFl); @@ -2061,7 +1959,10 @@ cmDtRC_t cmDataRecdParseId(cmData_t* p, cmErr_t* err, unsigned errRC, ... ) -//---------------------------------------------------------------------------- +//============================================================================ +//============================================================================ +//============================================================================ + unsigned _cmDataSerializeNodeByteCount( const cmData_t* p ) { unsigned n = 0; @@ -2161,10 +2062,32 @@ char* _cmDataSerializeWrite( cmData_t* np, char* dp, const char* ep ) return dp; } +char* _cmDataSerialize( const cmData_t* p, char* buf, const char* ep ) +{ + /* + buf = _cmDataSerializeWrite(p,buf,ep); + + // if this data type has a child then write the child + if( kMinStructDtId <= p->tid && p->tid <= kMaxStructDtId && p->u.child != NULL ) + buf = _cmDataSerialize(p->u.child,buf,ep); + + // if this data type has siblings then write sibings + cmData_t* dp = p->u.child; + for(; dp != NULL; dp=dp->sibling ) + buf = cmDataSerialize(dp->sibling,buf,ep); + + return buf; + */ + return NULL; +} + cmDtRC_t cmDataSerialize( const cmData_t* p, void* buf, unsigned bufByteCnt ) { - - + /* + const char* ep = (char*)p + bufByteCnt; + buf = _cmDataSerialize(p,buf,bufByteCnt); + assert( buf <= ep ); + */ return kOkDtRC; } @@ -2173,6 +2096,598 @@ cmDtRC_t cmDataDeserialize( const void* buf, unsigned bufByteCnt, cmData_t** pp return kOkDtRC; } +//============================================================================ +//============================================================================ +//============================================================================ +enum +{ + kLCurlyLexTId = kUserLexTId + 1, + kRCurlyLexTId, + kLParenLexTId, + kRParenLexTId, + kLBrackLexTId, + kRBrackLexTId, + kColonLexTId, + kCommaLexTId, +}; + +typedef struct +{ + unsigned id; + const cmChar_t* label; +} cmDtToken_t; + +cmDtToken_t _cmDtTokenArray[] = +{ + { kLCurlyLexTId, "{" }, + { kRCurlyLexTId, "}" }, + { kLBrackLexTId, "[" }, + { kRBrackLexTId, "]" }, + { kLParenLexTId, "(" }, + { kRParenLexTId, ")" }, + { kColonLexTId, ":" }, + { kCommaLexTId, "," }, + { kErrorLexTId,""} + +}; + +typedef struct +{ + cmErr_t err; + cmLexH lexH; + cmStackH_t stH; + +} cmDataParser_t; + + +cmDataParserH_t cmDataParserNullHandle = cmSTATIC_NULL_HANDLE; + +cmDataParser_t* _cmDataParserHandleToPtr( cmDataParserH_t h ) +{ + cmDataParser_t* p = (cmDataParser_t*)h.h; + assert( p!= NULL ); + return p; +} + +cmDtRC_t _cmDataParserDestroy( cmDataParser_t* p ) +{ + if( cmLexFinal(&p->lexH) != kOkLexRC ) + cmErrMsg(&p->err,kLexFailDtRC,"Lexer release failed."); + + if( cmStackFree(&p->stH) != kOkStRC ) + cmErrMsg(&p->err,kParseStackFailDtRC,"The data object parser stack release failed."); + + cmMemFree(p); + + return kOkDtRC; +} + +cmDtRC_t cmDataParserCreate( cmCtx_t* ctx, cmDataParserH_t* hp ) +{ + cmDtRC_t rc; + unsigned i; + + if((rc = cmDataParserDestroy(hp)) != kOkDtRC ) + return rc; + + cmDataParser_t* p = cmMemAllocZ(cmDataParser_t,1); + + cmErrSetup(&p->err,&ctx->rpt,"Data Parser"); + + if(cmLexIsValid(p->lexH = cmLexInit(NULL,0,0,&ctx->rpt))==false) + { + rc = cmErrMsg(&p->err, kLexFailDtRC, "The data object parser lexer create failed."); + goto errLabel; + } + + for(i=0; _cmDtTokenArray[i].id != kErrorLexTId; ++i) + if( cmLexRegisterToken(p->lexH, _cmDtTokenArray[i].id, _cmDtTokenArray[i].label) != kOkLexRC ) + { + rc = cmErrMsg(&p->err,kLexFailDtRC,"The data object parser lexer could not register the '%s' token.",_cmDtTokenArray[i].label); + goto errLabel; + } + + if( cmStackAlloc(ctx, &p->stH, 1024, 1024, sizeof(cmData_t*)) != kOkStRC ) + { + rc = cmErrMsg(&p->err,kParseStackFailDtRC,"The data object parser stack create failed."); + goto errLabel; + } + + hp->h = p; + + errLabel: + if( rc != kOkDtRC ) + _cmDataParserDestroy(p); + + return kOkDtRC; +} + +cmDtRC_t cmDataParserDestroy( cmDataParserH_t* hp ) +{ + cmDtRC_t rc=kOkDtRC; + + if( hp==NULL || cmDataParserIsValid(*hp)==false ) + return rc; + + cmDataParser_t* p = _cmDataParserHandleToPtr(*hp); + + if((rc = _cmDataParserDestroy(p)) != kOkDtRC ) + return rc; + + hp->h = NULL; + + return kOkDtRC; +} + + +bool cmDataParserIsValid( cmDataParserH_t h ) +{ return h.h != NULL; } + + + +// { +// id0 : scalar_value +// id1 : ( heterogenous, array, value ) +// id2 : [ homogeneous array values ] +// id3 : +// } + + +// flags describing the expected next token +enum +{ + kValueExpFl = 0x01, + kIdExpFl = 0x02, + kColonExpFl = 0x04, + kCommaExpFl = 0x08 +}; + +typedef struct +{ + cmData_t* dp; +} cmDataStEle_t; + +typedef struct +{ + cmDataParser_t* p; + cmData_t* cnp; + unsigned flags; + cmChar_t* tmpStr; + + unsigned arrayCnt; + void* arrayMem; + +} cmDataParserCtx_t; + +cmDtRC_t _cmDpSyntaxErrV( cmDataParserCtx_t* c, const cmChar_t* fmt, va_list vl ) +{ + cmChar_t* s0 = NULL; + cmChar_t* s1 = NULL; + s0 = cmTsVPrintfP(s0,fmt,vl); + s1 = cmMemAllocStrN(cmLexTokenText(c->p->lexH),cmLexTokenCharCount(c->p->lexH)); + cmDtRC_t rc = cmErrMsg(&c->p->err,kSyntaxErrDtRC,"Syntax error on line %i column:%i token:'%s'. %s",cmLexCurrentLineNumber(c->p->lexH),cmLexCurrentColumnNumber(c->p->lexH),s1,cmStringNullGuard(s0)); + cmMemFree(s0); + cmMemFree(s1); + return rc; +} + +cmDtRC_t _cmDpSyntaxErr( cmDataParserCtx_t* c, const cmChar_t* fmt, ... ) +{ + va_list vl; + va_start(vl,fmt); + cmDtRC_t rc = _cmDpSyntaxErrV(c,fmt,vl); + va_end(vl); + return rc; +} + +cmDtRC_t _cmDpPopStack( cmDataParserCtx_t* c, cmData_t** pp ) +{ + const void* vp; + if((vp = cmStackTop(c->p->stH)) == NULL ) + return _cmDpSyntaxErr(c,"Stack underflow."); + + if( cmStackPop(c->p->stH,1) != kOkStRC ) + return _cmDpSyntaxErr(c,"Stack pop failed."); + + *pp = *(cmData_t**)vp; + + //printf("pop: %p\n",*pp); + + return kOkDtRC; +} + +cmDtRC_t _cmDpPushStack( cmDataParserCtx_t* c, cmData_t* np ) +{ + //printf("push:%p\n",np); + + // store the current node + if( cmStackPush(c->p->stH, &np, 1 ) != kOkStRC ) + return _cmDpSyntaxErr(c,"Parser stack push failed."); + + return kOkDtRC; +} + +cmDtRC_t _cmDpStoreArrayEle( cmDataParserCtx_t* c, void* dp, unsigned eleByteCnt, unsigned tid ) +{ + if( c->cnp->tid == kVoidPtrDtId ) + c->cnp->tid = tid; + else + if( c->cnp->tid != tid ) + return _cmDpSyntaxErr(c,"Mixed types were detected in an array list."); + + unsigned newByteCnt = (c->cnp->cnt+1)*eleByteCnt; + char* vp = cmMemResizeP(char, c->cnp->u.vp, newByteCnt); + + memcpy(vp + c->cnp->cnt*eleByteCnt,dp,eleByteCnt); + c->cnp->u.vp = vp; + c->cnp->cnt += 1; + + c->flags = kValueExpFl | kCommaExpFl; + + return kOkDtRC; +} + +cmDtRC_t _cmDataParserOpenPair( cmDataParserCtx_t* c ) +{ + cmDtRC_t rc = kOkDtRC; + + assert( c->cnp->tid == kRecordDtId ); + + // create a pair with a 'null' value which will be replaced when the pair's value is parsed + cmData_t* nnp = cmDataAllocNull(NULL); + cmData_t* pnp = cmDataAllocPairLabelN( c->cnp, cmLexTokenText(c->p->lexH), cmLexTokenCharCount(c->p->lexH), nnp ); + + // store the current node + if((rc = _cmDpPushStack(c,c->cnp)) != kOkDtRC ) + return rc; + + // make the new pair the current node + c->cnp = pnp; + + // pair openings must be followed by a colon. + c->flags = kColonExpFl; + + return rc; +} + +cmDtRC_t _cmDataParserClosePair( cmDataParserCtx_t* c ) +{ + cmDtRC_t rc; + + // make the pair's parent record the current node + if((rc = _cmDpPopStack(c, &c->cnp )) != kOkDtRC ) + return rc; + + // pairs only occur in records + if( c->cnp->tid != kRecordDtId ) + return _cmDpSyntaxErr(c,"A 'pair' end was found outside of a 'record'."); + + // pairs must be followed by id's or comma's + c->flags = kIdExpFl | kCommaExpFl; + + return rc; +} + +cmDtRC_t _cmDpStoreValue( cmDataParserCtx_t* c, cmData_t* np, const cmChar_t* typeLabel ) +{ + assert( np != NULL ); + + cmDtRC_t rc = kOkDtRC; + + switch( c->cnp->tid ) + { + case kPairDtId: + + // assign the new node as the value of the pair + cmDataPairSetValue(c->cnp,np); + + // close the values parent pair + rc = _cmDataParserClosePair(c); + break; + + case kListDtId: + cmDataAppendChild(c->cnp,np); + c->flags = kValueExpFl; + break; + + default: + rc = _cmDpSyntaxErr(c,"A '%s' value was found outside of a valid container.",typeLabel); + + // Free the new data node because it was not attached and will + // otherwise be lost + cmDataFree(np); + + } + + c->flags |= kCommaExpFl; + + return rc; +} + +cmDtRC_t _cmDataParserReal( cmDataParserCtx_t* c ) +{ + cmDtRC_t rc = kOkDtRC; + bool floatFl = cmLexTokenIsSinglePrecision(c->p->lexH); + double dval; + float fval; + + if( floatFl ) + fval = cmLexTokenFloat(c->p->lexH); + else + dval = cmLexTokenDouble(c->p->lexH); + + + if( cmDataIsPtr(c->cnp) ) + { + if( floatFl ) + rc = _cmDpStoreArrayEle(c,&fval,sizeof(fval),kFloatPtrDtId); + else + rc = _cmDpStoreArrayEle(c,&dval,sizeof(dval),kDoublePtrDtId); + } + else + { + cmData_t* np = floatFl ? cmDataAllocFloat(NULL,fval) : cmDataAllocDouble(NULL,dval); + rc = _cmDpStoreValue(c,np,"real"); + } + return rc; +} + +cmDtRC_t _cmDataParserInt( cmDataParserCtx_t* c ) +{ + cmDtRC_t rc = kOkDtRC; + int val = cmLexTokenInt(c->p->lexH); + bool unsignedFl = cmLexTokenIsUnsigned(c->p->lexH); + + if( cmDataIsPtr(c->cnp) ) + rc = _cmDpStoreArrayEle(c,&val,sizeof(val),unsignedFl ? kUIntPtrDtId : kIntPtrDtId); + else + { + cmData_t* np = unsignedFl ? cmDataAllocUInt(NULL,val) : cmDataAllocInt(NULL,val); + rc = _cmDpStoreValue(c,np,"int"); + } + + return rc; +} + +cmDtRC_t _cmDataParserString( cmDataParserCtx_t* c ) +{ + // if we are expecting a pair label + if( cmIsFlag(c->flags,kIdExpFl) ) + return _cmDataParserOpenPair(c); + + // otherwise a 'value' must be expected + if( cmIsNotFlag(c->flags,kValueExpFl) ) + return _cmDpSyntaxErr(c,"Unexpected string."); + + cmData_t* np = cmDataConstStrAllocN(NULL,cmLexTokenText(c->p->lexH), cmLexTokenCharCount(c->p->lexH)); + + return _cmDpStoreValue(c,np,"string"); +} + +cmDtRC_t _cmDataParserOpenRecd( cmDataParserCtx_t* c ) +{ + cmDtRC_t rc = kOkDtRC; + + // records are values - so we must be expecting a value + if( cmIsFlag(c->flags,kValueExpFl) == false ) + return _cmDpSyntaxErr(c,"Unexpected '{'."); + + // store the current node + if((rc = _cmDpPushStack(c,c->cnp)) != kOkDtRC ) + return rc; + + // alloc a new record and make it the current node + if( (c->cnp = cmDataRecdAlloc(NULL)) == NULL ) + return _cmDpSyntaxErr(c,"'recd' allocate failed."); + + // new records must be followed by an id token. + c->flags = kIdExpFl; + + return rc; +} + +cmDtRC_t _cmDataParserCloseContainer( cmDataParserCtx_t* c, const cmChar_t* typeLabelStr ) +{ + cmDtRC_t rc; + + cmData_t* np = c->cnp; + + // make the parent node the new current node + if((rc = _cmDpPopStack(c,&c->cnp)) != kOkDtRC ) + return rc; + + return _cmDpStoreValue(c,np,typeLabelStr); +} + +cmDtRC_t _cmDataParserCloseRecd( cmDataParserCtx_t* c ) +{ + assert( c->cnp->tid == kRecordDtId ); + + return _cmDataParserCloseContainer(c,"record"); +} + +cmDtRC_t _cmDataParserOpenList( cmDataParserCtx_t* c ) +{ + cmDtRC_t rc = kOkDtRC; + + // lists are values - so we must be expecting a value + if( cmIsFlag(c->flags,kValueExpFl) == false ) + return _cmDpSyntaxErr(c,"Unexpected '('."); + + // store the current node + if((rc = _cmDpPushStack(c,c->cnp)) != kOkDtRC ) + return rc; + + // create a new list + if( (c->cnp = cmDataListAlloc(NULL)) == NULL ) + return _cmDpSyntaxErr(c,"'list' allocate failed."); + + // new lists must be followed by a value + c->flags = kValueExpFl; + + return rc; +} + +cmDtRC_t _cmDataParserCloseList( cmDataParserCtx_t* c ) +{ + assert( c->cnp->tid == kListDtId ); + return _cmDataParserCloseContainer(c,"list"); +} + +cmDtRC_t _cmDataParserOpenArray( cmDataParserCtx_t* c ) +{ + cmDtRC_t rc = kOkDtRC; + + // arrays are values - so we must be expecting a value + if( cmIsFlag(c->flags,kValueExpFl) == false ) + return _cmDpSyntaxErr(c,"Unexpected '('."); + + // store the current node + if((rc = _cmDpPushStack(c,c->cnp)) != kOkDtRC ) + return rc; + + // create a new array + if( (c->cnp = cmDataVoidAllocPtr(NULL, NULL, 0 )) == NULL ) + return _cmDpSyntaxErr(c,"'array' allocate failed."); + + // new arrays must be followed by a value + c->flags = kValueExpFl; + + return rc; + +} + +cmDtRC_t _cmDataParserCloseArray( cmDataParserCtx_t* c ) +{ + assert( cmDataIsPtr(c->cnp) ); + + return _cmDataParserCloseContainer(c,"array"); +} + +cmDtRC_t _cmDataParserOnColon( cmDataParserCtx_t* c ) +{ + // colons only follow field identifiers and are always followed by values. + if( cmIsFlag(c->flags,kColonExpFl) == false ) + return _cmDpSyntaxErr(c,"Unexpected colon."); + + c->flags = kValueExpFl; + + return kOkDtRC; +} + +cmDtRC_t _cmDataParserOnComma( cmDataParserCtx_t* c ) +{ + // comma's may be found in three places: + // 1) following field values + // 2) between list values + // 3) between array values + // comma's are always followed by values + if( cmIsFlag(c->flags,kCommaExpFl) == false ) + return _cmDpSyntaxErr(c, "Unexpected comma."); + + c->flags = kValueExpFl; + + return kOkDtRC; +} + + +cmDtRC_t cmDataParserExec( cmDataParserH_t h, const cmChar_t* text, cmData_t** pp ) +{ + cmDtRC_t rc = kOkDtRC; + cmDataParser_t* p = _cmDataParserHandleToPtr(h); + unsigned tokenId; + cmDataParserCtx_t ctx; + cmData_t* root = cmDataRecdAlloc(NULL); + ctx.cnp = root; + ctx.p = p; + ctx.flags = kIdExpFl; + + if( cmLexSetTextBuffer(p->lexH,text,strlen(text)) != kOkLexRC ) + return cmErrMsg(&p->err,kLexFailDtRC,"The data object lexer failed during reset."); + + cmStackClear(p->stH,false); + + while(rc==kOkDtRC && (tokenId = cmLexGetNextToken(p->lexH)) != kEofLexTId ) + { + switch(tokenId) + { + case kRealLexTId: // real number (contains a decimal point or is in scientific notation) + rc = _cmDataParserReal(&ctx); + break; + + case kIntLexTId: // decimal integer + case kHexLexTId: // hexidecimal integer + rc = _cmDataParserInt(&ctx); + break; + + case kIdentLexTId: // identifiers are treated as strings + case kQStrLexTId: // quoted string + rc = _cmDataParserString(&ctx); + break; + + case kLCurlyLexTId: // a new record is starting + rc = _cmDataParserOpenRecd(&ctx); + break; + + case kRCurlyLexTId: // the current record is finished + rc = _cmDataParserCloseRecd(&ctx); + break; + + case kLParenLexTId: // a list is starting + rc = _cmDataParserOpenList(&ctx); + break; + + case kRParenLexTId: // a list is finished + rc = _cmDataParserCloseList(&ctx); + break; + + case kLBrackLexTId: // an array is starting + rc = _cmDataParserOpenArray(&ctx); + break; + + case kRBrackLexTId: // an array is ending + rc = _cmDataParserCloseArray(&ctx); + break; + + case kColonLexTId: // the previous id was a field id + rc = _cmDataParserOnColon(&ctx); + break; + + case kCommaLexTId: // comma sep. for array or fields + rc = _cmDataParserOnComma(&ctx); + break; + + case kBlockCmtLexTId: // block comment + case kLineCmtLexTId: // line comment + case kErrorLexTId: // the lexer was unable to identify the current token + case kUnknownLexTId: // the token is of an unknown type (only used when kReturnUnknownLexFl is set) + case kEofLexTId: // the lexer reached the end of input + case kSpaceLexTId: // white space + { + rc = cmErrMsg(&p->err,kLexFailDtRC,"The data object lexer failed with an unexpected token '%s' on line '%i'.",cmLexIdToLabel(p->lexH,tokenId),cmLexCurrentLineNumber(p->lexH)); + goto errLabel; + } + } + } + + errLabel: + + if( rc == kOkDtRC ) + *pp = ctx.cnp; + else + { + if( ctx.cnp != root ) + cmDataUnlinkAndFree(ctx.cnp); + + cmDataUnlinkAndFree(root); + } + return rc; +} + +//============================================================================ +//============================================================================ +//============================================================================ + #define parr(rpt,fmt,arr,n) do{int i=0; cmRptPrintf(rpt,"[ "); for(;irpt,"Data Parser Tester"); + + if((rc = cmDataParserCreate(ctx, &h )) != kOkDtRC ) + { + rc = cmErrMsg(&err,rc,"Data parser create failed."); + goto errLabel; + } + + if( cmDataParserExec(h,text,&dp) != kOkDtRC ) + rc = cmErrMsg(&err,rc,"Data parser exec failed."); + else + if( dp != NULL ) + cmDataPrint(dp,&ctx->rpt); + + + errLabel: + if( cmDataParserDestroy( &h ) != kOkDtRC ) + { + rc = cmErrMsg(&err,rc,"Data parser destroy failed."); + goto errLabel; + } + + cmDataFree(dp); + + return rc; +} + + void cmDataTest( cmCtx_t* ctx ) { float farr[] = { 1.23, 45.6, 7.89 }; + cmDataParserTest(ctx); + return; + cmData_t* d0 = cmDataRecdAllocLabelA(NULL, "name",kConstStrDtId,"This is a string.", "id", kUIntDtId, 21, @@ -2291,4 +2853,4 @@ void cmDataTest( cmCtx_t* ctx ) cmRptPrintf(&ctx->rpt,"Done!.\n"); } - +#endif diff --git a/cmData.h b/cmData.h index dccdde2..0116183 100644 --- a/cmData.h +++ b/cmData.h @@ -5,129 +5,6 @@ extern "C" { #endif - enum - { - kOkDtRC = cmOkRC, - kCvtErrDtRC, - kVarArgErrDtRC, - kMissingFieldDtRC, - kEolDtRC - }; - - enum - { - kInvalidDtChar = 0xff, - kInvalidDtUChar = 0xff, - kInvalidDtShort = 0xffff, - kInvalidDtUShort = 0xffff, - kInvalidDtInt = 0xffffffff, - kInvalidDtUInt = 0xffffffff, - kInvalidDtLong = 0xffffffff, - kInvalidDtULong = 0xffffffff, - }; - - typedef enum - { - kInvalidDtId, - - kMinValDtId, - - kNullDtId = kMinValDtId, - kUCharDtId, - kCharDtId, - kUShortDtId, - kShortDtId, - kUIntDtId, - kIntDtId, - kULongDtId, - kLongDtId, - kFloatDtId, - kDoubleDtId, - - kStrDtId, - kConstStrDtId, - kMaxValDtId = kConstStrDtId, - - kMinPtrDtId, - kUCharPtrDtId = kMinPtrDtId, // cnt=array element count - kCharPtrDtId, - kUShortPtrDtId, - kShortPtrDtId, - kUIntPtrDtId, - kIntPtrDtId, - kULongPtrDtId, - kLongPtrDtId, - kFloatPtrDtId, - kDoublePtrDtId, - kVoidPtrDtId, - kMaxPtrDtId = kVoidPtrDtId, - - kMinStructDtId, - kListDtId = kMinStructDtId, // children nodes are array elements, cnt=child count - kPairDtId, // key/value pairs, cnt=2, first child is key, second is value - kRecordDtId, // children nodes are pairs, cnt=pair count - kMaxStructDtId, - - kOptArgDtFl = 0x80000000 - } cmDataFmtId_t; - - enum - { - kDynObjDtFl = 0x01, // object was dynamically allocated - kDynPtrDtFl = 0x02 // ptr array was dynamically allocated - }; - - typedef struct cmData_str - { - cmDataFmtId_t tid; // data format id - unsigned flags; // - struct cmData_str* parent; // this childs parent - struct cmData_str* sibling; // this childs left sibling - unsigned cnt; // array ele count - - union - { - char c; - unsigned char uc; - short s; - unsigned short us; - int i; - unsigned int ui; - long l; - unsigned long ul; - float f; - double d; - - cmChar_t* z; - const cmChar_t* cz; - - void* vp; - - char* cp; - unsigned char* ucp; - short* sp; - unsigned short* usp; - int* ip; - unsigned int* uip; - long* lp; - unsigned long* ulp; - float* fp; - double* dp; - - - struct cmData_str* child; // first child (array,record,pair) - } u; - - } cmData_t; - - typedef unsigned cmDtRC_t; - - extern cmData_t cmDataNull; - - bool cmDataIsValue( const cmData_t* p ); - bool cmDataIsPtr( const cmData_t* p ); - bool cmDataIsStruct( const cmData_t* p ); // is a pair,list or record - /* TODO: 0) Figure out a error handling scheme that does not rely on @@ -144,7 +21,7 @@ extern "C" { the array space. This will allow dynamic allocattion to occur at runtime. Make var args functions for list and record objects which also take this flag. - Where ever a function may be implemented using + Whereever a function may be implemented using static/dynamic allocation this flag should be present. (e.g. string allocation for pair labels) This choice is common enough that it may be worth @@ -170,40 +47,227 @@ extern "C" { */ - bool canConvertType( cmDataFmtId_t srcId, cmDataFmtId_t dstId ); - bool willTruncate( cmDataFmtId_t srcId, cmDataFmtId_t dstId ); - bool canConvertObj( const cmData_t* srcObj, cmData_t* dstObj ); - bool willTruncateObj(const cmData_t* srcObj, cmData_t* dstObj ); - + enum + { + kOkDtRC = cmOkRC, + kAssertErrDtRC, + kConstErrDtRC, + kCvtErrDtRC, + kInvalidContDtRC, + kInvalidTypeDtRC, + kEolDtRC + }; + + typedef unsigned cmDtRC_t; + + typedef enum + { + kInvalidTypeDtId,// 0 + kNullDtId, // 1 the data object exists but it has no data + kUCharDtId, // 2 + kCharDtId, // 3 + kUShortDtId, // 4 + kShortDtId, // 5 + kUIntDtId, // 6 + kIntDtId, // 7 + kULongDtId, // 8 + kLongDtId, // 9 + kFloatDtId, // 10 + kDoubleDtId, // 11 + kStrDtId, // 12 zero terminated string + kBlobDtId, // 13 application defined raw memory object + kStructDtId // 14 node is a pair,list, or recd + } cmDataTypeId_t; + + + typedef enum + { + kInvalidCntDtId, // 0 + kScalarDtId, // 1 + kArrayDtId, // 2 + kPairDtId, // 3 + kListDtId, // 4 + kRecordDtId // 5 + } cmDataContainerId_t; + + enum + { + kNoFlagsDtFl = 0x00, + + // Indicate that the memory used by the data object + // was dynamically allocated and should be released + // by cmDataFree(). + kFreeObjDtFl = 0x01, + + // Indicate that the memory used by strings, blobs + // and arrays should be freed by cmDataFree(). + kFreeValueDtFl = 0x02, + + // Indicate that the value of the object cannot be changed. + // (but the object could be reassigned as a new type). + kConstValueDtFl = 0x04, + + // Indicate that the type of the object cannot be changed. + // (but the value may be changed). + kConstObjDtFl = 0x08, + + // Indicate that the array or string should not be + // internally reallocated but rather the source pointer + // should be taken as the new value of the object. + kNoCopyDtFl = 0x10, + + + }; + + + typedef struct cmData_str + { + cmDataTypeId_t tid; // data format id + cmDataContainerId_t cid; // container id + unsigned flags; // + struct cmData_str* parent; // this childs parent + struct cmData_str* sibling; // this childs left sibling + unsigned cnt; // byte cnt for strings/blobs and ele count for arrays + + union + { + char c; + unsigned char uc; + short s; + unsigned short us; + int i; + unsigned int ui; + long l; + unsigned long ul; + float f; + double d; + + cmChar_t* z; + + void* vp; + + /* + char* cp; + unsigned char* ucp; + short* sp; + unsigned short* usp; + int* ip; + unsigned int* uip; + long* lp; + unsigned long* ulp; + float* fp; + double* dp; + */ + + struct cmData_str* child; // first child (list,record,pair) + } u; + + } cmData_t; + + extern cmData_t cmDataNull; + + const cmChar_t* cmDataTypeToLabel( cmDataTypeId_t tid ); + cmDataTypeId_t cmDataLabelToType( const cmChar_t* typeLabelStr ); + + // Returns 1 for kStrDtId. + // Returns cmInvalidCnt if tid is not recognized. + unsigned dmDataByteWidth( cmDataTypeId_t tid ); + + const cmChar_t* cmDataContainerIdToLabel( cmDataContainerId_t tid ); + cmDataContainerId_t cmDataLabelToContainerId( const cmChar_t* contLabelStr ); + + bool cmDataIsConstObj( const cmData_t* d ); + void cmDataEnableConstObj( cmData_t* d, bool enaFl ); + + bool cmDataIsConstValue( const cmData_t* d ); + void cmDataEnableConstValue( cmData_t* d, bool enaFl ); + + bool cmDataIsFreeValue( const cmData_t* d ); + void cmDataEnableFreeValue( cmData_t* d, bool enaFl ); + + // Returns true if this is a scalar or array node. + bool cmDataIsLeaf( const cmData_t* d); + + // Return true if this is NOT a scalar or array node. + bool cmDataIsStruct( const cmData_t* d ); + - // Get the value of an object without conversion. - // The data type id must match the return type or the - // conversion must be an automatic C conversion. - char cmDataChar( const cmData_t* p ); - unsigned char cmDataUChar( const cmData_t* p ); - short cmDataShort( const cmData_t* p ); - unsigned short cmDataUShort( const cmData_t* p ); - int cmDataInt( const cmData_t* p ); - unsigned int cmDataUInt( const cmData_t* p ); - long cmDataLong( const cmData_t* p ); - unsigned long cmDataULong( const cmData_t* p ); - float cmDataFloat( const cmData_t* p ); - double cmDataDouble( const cmData_t* p ); - cmChar_t* cmDataStr( const cmData_t* p ); - const cmChar_t* cmDataConstStr( const cmData_t* p ); - void* cmDataVoidPtr( const cmData_t* p ); - char* cmDataCharPtr( const cmData_t* p ); - unsigned char* cmDataUCharPtr( const cmData_t* p ); - short* cmDataShortPtr( const cmData_t* p ); - unsigned short* cmDataUShortPtr( const cmData_t* p ); - int* cmDataIntPtr( const cmData_t* p ); - unsigned int* cmDataUIntPtr( const cmData_t* p ); - long* cmDataLongPtr( const cmData_t* p ); - unsigned long* cmDataULongPtr( const cmData_t* p ); - float* cmDataFloatPtr( const cmData_t* p ); - double* cmDataDoublePtr( const cmData_t* p ); + //---------------------------------------------------------------------------- + // Scalar related functions + // + // Dynamically allocate a scalar object and set it's value. + // The 'flags' argument may include kConstValueDtFl and kConstObjDtFl. + // The string and blob constructors may also use the + // kNoCopyDtFl and the kFreeValueDtFl. + + // Generic: + // 'byteCnt' is ignored for all types other than strings and blobs. + cmDtRC_t cmDataNewScalar( cmData_t* parent, cmDataTypeId_t tid, unsigned flags, void* vp, unsigned byteCnt, cmData_t** ref ); + + // Type specific + cmDtRC_t cmDataNewNull( cmData_t* parent, unsigned flags, cmData_t** ref ); + cmDtRC_t cmDataNewChar( cmData_t* parent, unsigned flags, char v, cmData_t** ref ); + cmDtRC_t cmDataNewUChar( cmData_t* parent, unsigned flags, unsigned char v, cmData_t** ref ); + cmDtRC_t cmDataNewShort( cmData_t* parent, unsigned flags, short v, cmData_t** ref ); + cmDtRC_t cmDataNewUShort( cmData_t* parent, unsigned flags, unsigned short v, cmData_t** ref ); + cmDtRC_t cmDataNewInt( cmData_t* parent, unsigned flags, int v, cmData_t** ref ); + cmDtRC_t cmDataNewUInt( cmData_t* parent, unsigned flags, unsigned int v, cmData_t** ref ); + cmDtRC_t cmDataNewLong( cmData_t* parent, unsigned flags, long v, cmData_t** ref ); + cmDtRC_t cmDataNewULong( cmData_t* parent, unsigned flags, unsigned long v, cmData_t** ref ); + cmDtRC_t cmDataNewFloat( cmData_t* parent, unsigned flags, float v, cmData_t** ref ); + cmDtRC_t cmDataNewDouble( cmData_t* parent, unsigned flags, double v, cmData_t** ref ); + cmDtRC_t cmDataNewStr( cmData_t* parent, unsigned flags, cmChar_t* str, cmData_t** ref ); + cmDtRC_t cmDataNewConstStr( cmData_t* parent, unsigned flags, const cmChar_t* str, cmData_t** ref ); + cmDtRC_t cmDataNewStrN( cmData_t* parent, unsigned flags, cmChar_t* str, unsigned charCnt, cmData_t** ref ); + cmDtRC_t cmDataNewConstStrN(cmData_t* parent, unsigned flags, const cmChar_t* str, unsigned charCnt, cmData_t** ref ); + cmDtRC_t cmDataNewBlob( cmData_t* parent, unsigned flags, void* vp, unsigned byteCnt, cmData_t** ref ); + cmDtRC_t cmDataNewConstBlob(cmData_t* parent, unsigned flags, const void* vp, unsigned byteCnt, cmData_t** ref ); + + + + // Set the value and type of an existing scalar object. + // These functions begin by releasing any resources held by *p + // prior to resetting the type and value of the object. + // The 'flags' argument to cmDataSetStr() and cmDataSetConstStr() + // may use the kNoCopyDtFl and the kFreeValueDtFl + cmDtRC_t cmDataSetScalarValue( cmData_t* d, cmDataTypeId_t tid, void* vp, unsigned byteCnt, unsigned flags ); + + cmDtRC_t cmDataSetNull( cmData_t* p ); + cmDtRC_t cmDataSetChar( cmData_t* p, char v ); + cmDtRC_t cmDataSetUChar( cmData_t* p, unsigned char v ); + cmDtRC_t cmDataSetShort( cmData_t* p, short v ); + cmDtRC_t cmDataSetUShort( cmData_t* p, unsigned short v ); + cmDtRC_t cmDataSetInt( cmData_t* p, int v ); + cmDtRC_t cmDataSetUInt( cmData_t* p, unsigned int v ); + cmDtRC_t cmDataSetLong( cmData_t* p, long v ); + cmDtRC_t cmDataSetULong( cmData_t* p, unsigned long v ); + cmDtRC_t cmDataSetFloat( cmData_t* p, float v ); + cmDtRC_t cmDataSetDouble( cmData_t* p, double v ); + cmDtRC_t cmDataSetStr( cmData_t* p, unsigned flags, cmChar_t* s ); + cmDtRC_t cmDataSetConstStr( cmData_t* p, unsigned flags, const cmChar_t* s ); + cmDtRC_t cmDataSetStrN( cmData_t* p, unsigned flags, cmChar_t* s, unsigned charCnt ); + cmDtRC_t cmDataSetConstStrN( cmData_t* p, unsigned flags, const cmChar_t* s, unsigned charCnt ); + cmDtRC_t cmDataSetBlob( cmData_t* p, unsigned flags, void* v, unsigned byteCnt ); + cmDtRC_t cmDataSetConstBlob( cmData_t* p, unsigned flags, const void* v, unsigned byteCnt ); + + // Get the value of an object. No conversion is applied the + // type must match exactly or an error is generated. + cmDtRC_t cmDataChar( const cmData_t* p, char* v ); + cmDtRC_t cmDataUChar( const cmData_t* p, unsigned char* v ); + cmDtRC_t cmDataShort( const cmData_t* p, short* v ); + cmDtRC_t cmDataUShort( const cmData_t* p, unsigned short* v ); + cmDtRC_t cmDataInt( const cmData_t* p, int* v ); + cmDtRC_t cmDataUInt( const cmData_t* p, unsigned int* v ); + cmDtRC_t cmDataLong( const cmData_t* p, long* v ); + cmDtRC_t cmDataULong( const cmData_t* p, unsigned long* v ); + cmDtRC_t cmDataFloat( const cmData_t* p, float* v ); + cmDtRC_t cmDataDouble( const cmData_t* p, double* v ); + cmDtRC_t cmDataStr( const cmData_t* p, cmChar_t** v ); + cmDtRC_t cmDataConstStr( const cmData_t* p, const cmChar_t** v ); + cmDtRC_t cmDataBlob( const cmData_t* p, cmChar_t** v, unsigned* byteCntRef ); + cmDtRC_t cmDataConstBlob( const cmData_t* p, const cmChar_t** v, unsigned* byteCntRef ); // Get the value of an object with conversion. cmDtRC_t cmDataGetChar( const cmData_t* p, char* v ); @@ -217,125 +281,96 @@ extern "C" { cmDtRC_t cmDataGetFloat( const cmData_t* p, float* v ); cmDtRC_t cmDataGetDouble( const cmData_t* p, double* v ); - // Returns the pointer - does not copy the data. - cmDtRC_t cmDataGetStr( const cmData_t* p, char** v ); - cmDtRC_t cmDataGetConstStr( const cmData_t* p, const char** v ); - cmDtRC_t cmDataGetVoidPtr( const cmData_t* p, void** v ); - cmDtRC_t cmDataGetCharPtr( const cmData_t* p, char** v ); - cmDtRC_t cmDataGetUCharPtr( const cmData_t* p, unsigned char** v ); - cmDtRC_t cmDataGetShortPtr( const cmData_t* p, short** v ); - cmDtRC_t cmDataGetUShortPtr( const cmData_t* p, unsigned short** v ); - cmDtRC_t cmDataGetIntPtr( const cmData_t* p, int** v ); - cmDtRC_t cmDataGetUIntPtr( const cmData_t* p, unsigned int** v ); - cmDtRC_t cmDataGetLongPtr( const cmData_t* p, long** v ); - cmDtRC_t cmDataGetULongPtr( const cmData_t* p, unsigned long** v ); - cmDtRC_t cmDataGetFloatPtr( const cmData_t* p, float** v ); - cmDtRC_t cmDataGetDoublePtr( const cmData_t* p, double** v ); + //---------------------------------------------------------------------------- + // Array related functions + // - // Set the value and type of an existing scalar object. + // Notes: + // 1) string arrays are arrays of string pointers. + // 2) blob arrays (array of void pointers) are not supported because + // there is no direct way to determine the length of each blob + // and therefore they cannot be internally duplicated - a special scheme + // could be devised (length goes in first 4 bytes) to make this + // work but we will defer that until the need arises. + + // + // Dynamically allocate a new array data object. + // + // eleCnt referes to the number of elements in the array pointed + // to by 'vp'. The number of bytes pointed to by 'vp' is then + // cmDataByteWidth(tid)*eleCnt. + // + // If no flags are set then the array pointed to by 'vp' is reallocated + // and kDataFreeDtFl is set. + // + // If kFreeValueDtFl is set then the object will take responsibility for + // releasing the memory pointed to by 'vp' when the object is destroyed + // or the array is reassigned. + // + // If kNoCopyDtFl is set then 'vp' becomes the internal array + // value (vp[cnt]) is NOT reallocated). In this case the client is + // responsibile for eventually releasing the associated memory - when + // the data object is no longer valid. + cmDtRC_t cmDataNewArray( cmData_t* parent, cmDataTypeId_t tid, void* vp, unsigned eleCnt, unsigned flags, cmData_t** ref ); + + cmDtRC_t cmDataNewCharArray( cmData_t* parent, char* v, unsigned eleCnt, unsigned flags, cmData_t** ref ); + cmDtRC_t cmDataNewUCharArray( cmData_t* parent, unsigned char* v, unsigned eleCnt, unsigned flags, cmData_t** ref ); + cmDtRC_t cmDataNewShortArray( cmData_t* parent, short* v, unsigned eleCnt, unsigned flags, cmData_t** ref ); + cmDtRC_t cmDataNewUShortArray( cmData_t* parent, unsigned short* v, unsigned eleCnt, unsigned flags, cmData_t** ref ); + cmDtRC_t cmDataNewIntArray( cmData_t* parent, int* v, unsigned eleCnt, unsigned flags, cmData_t** ref ); + cmDtRC_t cmDataNewUIntArray( cmData_t* parent, unsigned int* v, unsigned eleCnt, unsigned flags, cmData_t** ref ); + cmDtRC_t cmDataNewLongArray( cmData_t* parent, long* v, unsigned eleCnt, unsigned flags, cmData_t** ref ); + cmDtRC_t cmDataNewULongArray( cmData_t* parent, unsigned long* v, unsigned eleCnt, unsigned flags, cmData_t** ref ); + cmDtRC_t cmDataNewFloatArray( cmData_t* parent, float* v, unsigned eleCnt, unsigned flags, cmData_t** ref ); + cmDtRC_t cmDataNewDoubleArray( cmData_t* parent, double* v, unsigned eleCnt, unsigned flags, cmData_t** ref ); + cmDtRC_t cmDataNewStrArray( cmData_t* parent, cmChar_t** v, unsigned eleCnt, unsigned flags, cmData_t** ref ); + cmDtRC_t cmDataNewConstStrArray( cmData_t* parent, const cmChar_t** v,unsigned eleCnt, unsigned flags, cmData_t** ref ); + + // Set the value and type of an existing scalar object. + // // These functions begin by releasing any resources held by *p // prior to resetting the type and value of the object. - cmData_t* cmDataSetNull( cmData_t* p ); - cmData_t* cmDataSetChar( cmData_t* p, char v ); - cmData_t* cmDataSetUChar( cmData_t* p, unsigned char v ); - cmData_t* cmDataSetShort( cmData_t* p, short v ); - cmData_t* cmDataSetUShort( cmData_t* p, unsigned short v ); - cmData_t* cmDataSetInt( cmData_t* p, int v ); - cmData_t* cmDataSetUInt( cmData_t* p, unsigned int v ); - cmData_t* cmDataSetLong( cmData_t* p, long v ); - cmData_t* cmDataSetULong( cmData_t* p, unsigned long v ); - cmData_t* cmDataSetFloat( cmData_t* p, float v ); - cmData_t* cmDataSetDouble( cmData_t* p, double v ); - cmData_t* cmDataSetStr( cmData_t* p, cmChar_t* s ); - cmData_t* cmDataSetConstStr( cmData_t* p, const cmChar_t* s ); + // The 'flags' argument may include kConstValueDtFl, kConstObjDtFl, + // kNoCopyDtFl and the kFreeValueDtFl. - // Set the type and value of an existing data object to an external array. - // These functions begin by releasing any resources help by *p. - // The array pointed to by 'vp' is not copied or duplicated. - // 'vp' is simply assigned as the data space for the object and therefore must remain - // valid for the life of the object. - cmData_t* cmDataSetVoidPtr( cmData_t* p, void* vp, unsigned cnt ); - cmData_t* cmDataSetCharPtr( cmData_t* p, char* vp, unsigned cnt ); - cmData_t* cmDataSetUCharPtr( cmData_t* p, unsigned char* vp, unsigned cnt ); - cmData_t* cmDataSetShortPtr( cmData_t* p, short* vp, unsigned cnt ); - cmData_t* cmDataSetUShortPtr( cmData_t* p, unsigned short* vp, unsigned cnt ); - cmData_t* cmDataSetIntPtr( cmData_t* p, int* vp, unsigned cnt ); - cmData_t* cmDataSetUIntPtr( cmData_t* p, unsigned int* vp, unsigned cnt ); - cmData_t* cmDataSetLongPtr( cmData_t* p, long* vp, unsigned cnt ); - cmData_t* cmDataSetULongPtr( cmData_t* p, unsigned long* vp, unsigned cnt ); - cmData_t* cmDataSetFloatPtr( cmData_t* p, float* vp, unsigned cnt ); - cmData_t* cmDataSetDoublePtr( cmData_t* p, double* vp, unsigned cnt ); + // Generic set array functions. 'vp' is assumed to point to an array + // of the type defined by 'tid'. + cmDtRC_t cmDataSetArrayValue( cmData_t* dt, cmDataTypeId_t tid, void* vp, unsigned eleCnt, unsigned flags ); - // Set the value of an existing array based data object. - // These functions begin by releasing any resources help by *p - // and then dynamically allocate the internal array and copy - // the array data into it. - cmData_t* cmDataSetStrAlloc( cmData_t* p, const cmChar_t* s ); - cmData_t* cmDataSetConstStrAlloc( cmData_t* p, const cmChar_t* s ); - cmData_t* cmDataSetVoidAllocPtr( cmData_t* p, const void* vp, unsigned cnt ); - cmData_t* cmDataSetCharAllocPtr( cmData_t* p, const char* vp, unsigned cnt ); - cmData_t* cmDataSetUCharAllocPtr( cmData_t* p, const unsigned char* vp, unsigned cnt ); - cmData_t* cmDataSetShortAllocPtr( cmData_t* p, const short* vp, unsigned cnt ); - cmData_t* cmDataSetUShortAllocPtr( cmData_t* p, const unsigned short* vp, unsigned cnt ); - cmData_t* cmDataSetIntAllocPtr( cmData_t* p, const int* vp, unsigned cnt ); - cmData_t* cmDataSetUIntAllocPtr( cmData_t* p, const unsigned int* vp, unsigned cnt ); - cmData_t* cmDataSetLongAllocPtr( cmData_t* p, const long* vp, unsigned cnt ); - cmData_t* cmDataSetULongAllocPtr( cmData_t* p, const unsigned long* vp, unsigned cnt ); - cmData_t* cmDataSetFloatAllocPtr( cmData_t* p, const float* vp, unsigned cnt ); - cmData_t* cmDataSetDoubleAllocPtr( cmData_t* p, const double* vp, unsigned cnt ); + // Type sepctific set array functions. + cmDtRC_t cmDataSetCharArray( cmData_t* d, char* v, unsigned eleCnt, unsigned flags ); + cmDtRC_t cmDataSetUCharArray( cmData_t* d, unsigned char* v, unsigned eleCnt, unsigned flags ); + cmDtRC_t cmDataSetShortArray( cmData_t* d, short* v, unsigned eleCnt, unsigned flags ); + cmDtRC_t cmDataSetUShortArray( cmData_t* d, unsigned short* v, unsigned eleCnt, unsigned flags ); + cmDtRC_t cmDataSetIntArray( cmData_t* d, int* v, unsigned eleCnt, unsigned flags ); + cmDtRC_t cmDataSetUIntArray( cmData_t* d, unsigned int* v, unsigned eleCnt, unsigned flags ); + cmDtRC_t cmDataSetLongArray( cmData_t* d, long* v, unsigned eleCnt, unsigned flags ); + cmDtRC_t cmDataSetULongArray( cmData_t* d, unsigned long* v, unsigned eleCnt, unsigned flags ); + cmDtRC_t cmDataSetFloatArray( cmData_t* d, float* v, unsigned eleCnt, unsigned flags ); + cmDtRC_t cmDataSetDoubleArray( cmData_t* d, double* v, unsigned eleCnt, unsigned flags ); + cmDtRC_t cmDataSetStrArray( cmData_t* d, cmChar_t** v, unsigned eleCnt, unsigned flags ); + cmDtRC_t cmDataSetConstStrArray(cmData_t* d,const cmChar_t** v,unsigned eleCnt, unsigned flags ); + + // Return the count of elements in a n array. + unsigned cmDataArrayEleCount( const cmData_t* d ); + + // Get a pointer to the base of an array. + // The type must match exactly or an error is generated. + // Use cmDataEleCount() to determine the number of elements in the array. + cmDtRC_t cmDataCharArray( const cmData_t* d, char** v ); + cmDtRC_t cmDataUCharArray( const cmData_t* d, unsigned char** v ); + cmDtRC_t cmDataShortArray( const cmData_t* d, short** v ); + cmDtRC_t cmDataUShortArray( const cmData_t* d, unsigned short** v ); + cmDtRC_t cmDataIntArray( const cmData_t* d, int** v ); + cmDtRC_t cmDataUIntArray( const cmData_t* d, unsigned int** v ); + cmDtRC_t cmDataLongArray( const cmData_t* d, long** v ); + cmDtRC_t cmDataULongArray( const cmData_t* d, unsigned long** v ); + cmDtRC_t cmDataFloatArray( const cmData_t* d, float** v ); + cmDtRC_t cmDataDoubleArray( const cmData_t* d, double** v ); + cmDtRC_t cmDataStrArray( const cmData_t* d, cmChar_t*** v ); + cmDtRC_t cmDataConstStrArray( const cmData_t* d, const cmChar_t*** v ); - - // Dynamically allocate a data object and set it's value. - cmData_t* cmDataAllocNull( cmData_t* parent ); - cmData_t* cmDataAllocChar( cmData_t* parent, char v ); - cmData_t* cmDataAllocUChar( cmData_t* parent, unsigned char v ); - cmData_t* cmDataAllocShort( cmData_t* parent, short v ); - cmData_t* cmDataAllocUShort( cmData_t* parent, unsigned short v ); - cmData_t* cmDataAllocInt( cmData_t* parent, int v ); - cmData_t* cmDataAllocUInt( cmData_t* parent, unsigned int v ); - cmData_t* cmDataAllocLong( cmData_t* parent, long v ); - cmData_t* cmDataAllocULong( cmData_t* parent, unsigned long v ); - cmData_t* cmDataAllocFloat( cmData_t* parent, float v ); - cmData_t* cmDataAllocDouble( cmData_t* parent, double v ); - - // Dynamically allocate a data object and set its array value to an external - // array. v[cnt] is assigned as the internal data space for the object and - // therefore must remain valid for the life of the object. - // See the cmDataXXXAlocPtr() for equivalent functions which dynamically - // allocate the intenal data space. - cmData_t* cmDataAllocStr( cmData_t* parent, cmChar_t* str ); - cmData_t* cmDataAllocConstStr( cmData_t* parent, const cmChar_t* str ); - cmData_t* cmDataAllocCharPtr( cmData_t* parent, char* v, unsigned cnt ); - cmData_t* cmDataAllocUCharPtr( cmData_t* parent, unsigned char* v, unsigned cnt ); - cmData_t* cmDataAllocShortPtr( cmData_t* parent, short* v, unsigned cnt ); - cmData_t* cmDataAllocUShortPtr( cmData_t* parent, unsigned short* v, unsigned cnt ); - cmData_t* cmDataAllocIntPtr( cmData_t* parent, int* v, unsigned cnt ); - cmData_t* cmDataAllocUIntPtr( cmData_t* parent, unsigned int* v, unsigned cnt ); - cmData_t* cmDataAllocLongPtr( cmData_t* parent, long* v, unsigned cnt ); - cmData_t* cmDataAllocULongPtr( cmData_t* parent, unsigned long* v, unsigned cnt ); - cmData_t* cmDataAllocFloatPtr( cmData_t* parent, float* v, unsigned cnt ); - cmData_t* cmDataAllocDoublePtr( cmData_t* parent, double* v, unsigned cnt ); - cmData_t* cmDataAllocVoidPtr( cmData_t* parent, void* v, unsigned cnt ); - - - // Dynamically allocate a data object and its array value. - // These functions dynamically allocate the internal array data space - // and copy v[cnt] into it. - cmData_t* cmDataStrAlloc( cmData_t* parent, cmChar_t* str ); - cmData_t* cmDataConstStrAlloc( cmData_t* parent, const cmChar_t* str ); - cmData_t* cmDataCharAllocPtr( cmData_t* parent, const char* v, unsigned cnt ); - cmData_t* cmDataUCharAllocPtr( cmData_t* parent, const unsigned char* v, unsigned cnt ); - cmData_t* cmDataShortAllocPtr( cmData_t* parent, const short* v, unsigned cnt ); - cmData_t* cmDataUShortAllocPtr( cmData_t* parent, const unsigned short* v, unsigned cnt ); - cmData_t* cmDataIntAllocPtr( cmData_t* parent, const int* v, unsigned cnt ); - cmData_t* cmDataUIntAllocPtr( cmData_t* parent, const unsigned int* v, unsigned cnt ); - cmData_t* cmDataLongAllocPtr( cmData_t* parent, const long* v, unsigned cnt ); - cmData_t* cmDataULongAllocPtr( cmData_t* parent, const unsigned long* v, unsigned cnt ); - cmData_t* cmDataFloatAllocPtr( cmData_t* parent, const float* v, unsigned cnt ); - cmData_t* cmDataDoubleAllocPtr( cmData_t* parent, const double* v, unsigned cnt ); - cmData_t* cmDataVoidAllocPtr( cmData_t* parent, const void* v, unsigned cnt ); - //---------------------------------------------------------------------------- // Structure related functions // @@ -428,6 +463,7 @@ extern "C" { cmData_t* cmDataAllocPairId( cmData_t* parent, unsigned keyId, cmData_t* value ); // Dynamically allocate the label but link (w/o realloc) the value. + cmData_t* cmDataAllocPairLabelN(cmData_t* parent, const cmChar_t* label, unsigned charCnt, cmData_t* value); cmData_t* cmDataAllocPairLabel( cmData_t* parent, const cmChar_t* label, cmData_t* value ); //---------------------------------------------------------------------------- @@ -445,15 +481,15 @@ extern "C" { // Var-args fmt: - // {} + // {} {} // scalar types: is literal, is not included // null has no or - // ptr types: is pointer, is element count - // struct types: is cmData_t, is not included + // array types: is pointer, is element count + // struct types: is cmData_t, and is not included // Indicate the end of argument list by setting to kInvalidDtId. // The memory for array based data types is dynamically allocated. - cmData_t* cmDataListAllocV(cmData_t* parent, va_list vl ); - cmData_t* cmDataListAllocA(cmData_t* parent, ... ); + cmRC_t cmDataListAllocV(cmData_t* parent, cmData_t** ref, va_list vl ); + cmRC_t cmDataListAllocA(cmData_t* parent, cmData_t** ref, ... ); // Returns a ptr to 'ele'. cmData_t* cmDataListAppendEle( cmData_t* p, cmData_t* ele ); @@ -464,9 +500,6 @@ extern "C" { cmData_t* cmDataListInsertEle( cmData_t* p, unsigned index, cmData_t* ele ); cmData_t* cmDataListInsertEleN(cmData_t* p, unsigned index, cmData_t* ele[], unsigned n ); - cmData_t* cmDataListUnlink( cmData_t* p, unsigned index ); - cmData_t* cmDataListFree( cmData_t* p, unsigned index ); - //---------------------------------------------------------------------------- // Record related functions // @@ -487,17 +520,17 @@ extern "C" { unsigned cmDataRecdKeyId( cmData_t* p, unsigned index ); const cmChar_t* cmDataRecdKeyLabel( cmData_t* p, unsigned index ); - cmData_t* cmRecdMake( cmData_t* parent, cmData_t* p ); - cmData_t* cmRecdAlloc( cmData_t* parent ); + cmData_t* cmDataRecdMake( cmData_t* parent, cmData_t* p ); + cmData_t* cmDataRecdAlloc( cmData_t* parent ); // Append a pair node by linking the pair node 'pair' to the record node 'p'. // 'pair' is simply linked to 'p' via cmDataAppendChild() no // reallocation or duplicattion takes place. - cmData_t* cmRecdAppendPair( cmData_t* p, cmData_t* pair ); + cmData_t* cmDataRecdAppendPair( cmData_t* p, cmData_t* pair ); // Var-args format: - // {} + // {} {} // scalar types: is literal, is not included // null type: has no or // ptr types: is pointer, is element count @@ -529,13 +562,28 @@ extern "C" { unsigned cmDataSerializeByteCount( const cmData_t* p ); cmDtRC_t cmDataSerialize( const cmData_t* p, void* buf, unsigned bufByteCnt ); cmDtRC_t cmDataDeserialize( const void* buf, unsigned bufByteCnt, cmData_t** pp ); + + //----------------------------------------------------------------------------- + typedef cmHandle_t cmDataParserH_t; + //static cmDataParserH_t cmDataParserNullHandle; + + cmDtRC_t cmDataParserCreate( cmCtx_t* ctx, cmDataParserH_t* hp ); + cmDtRC_t cmDataParserDestroy( cmDataParserH_t* hp ); + bool cmDataParserIsValid( cmDataParserH_t h ); + + // Parse a text representation into a 'record' type. + // Note that the text is wrapped with implied curly braces + // (e.g. "{ text }"). The contents of the text should therefore + // fit the record syntax (e.g. the first token should be a + // 'pair' label. + cmDtRC_t cmDataParserExec( cmDataParserH_t h, const cmChar_t* text, cmData_t** pp ); + //----------------------------------------------------------------------------- void cmDataPrint( const cmData_t* p, cmRpt_t* rpt ); void cmDataTest( cmCtx_t* ctx ); - #ifdef __cplusplus } #endif diff --git a/cmGrPage.h b/cmGrPage.h index 1f71873..6d7fd40 100644 --- a/cmGrPage.h +++ b/cmGrPage.h @@ -60,7 +60,11 @@ extern "C" { // Draw the page. void cmGrPageDraw( cmGrPgH_t h, cmGrDcH_t dcH ); + // Label callback functions are used to translate numeric axis values to + // text strings. Multiple label callback functions can be registered with + // a page and then assigned to a given view axis via cmGrViewSetLabelFunc(). typedef void (*cmGrLabelFunc_t)( void* arg, cmChar_t* label, unsigned labelCharCnt, cmGrV_t value ); + // Returns id of the new page label function. unsigned cmGrPageLabelFuncRegister( cmGrPgH_t h, cmGrLabelFunc_t func, void* arg, const cmChar_t* label ); unsigned cmGrPageLabelFuncCount( cmGrPgH_t h ); diff --git a/cmLex.c b/cmLex.c index 7e9eb89..0ea0f35 100644 --- a/cmLex.c +++ b/cmLex.c @@ -7,6 +7,12 @@ #include "cmMallocDebug.h" #include "cmFile.h" +enum +{ + kRealFloatLexFl = 0x01, + kIntUnsignedLexFl = 0x02 +}; + typedef struct { unsigned code; @@ -29,6 +35,7 @@ cmLexErrorRecd cmLexErrorArray[] = { kMemAllocErrLexRC, "An attempted memory allocation failed"}, { kEofRC, "The end of the input text was encountered (this is a normal condition not an error)"}, { kInvalidLexTIdLexRC, "An invalid token id was encountered."}, + { kSignErrorLexRC, "A signed integer has a 'u' or 'U' suffix."}, { kInvalidLexRC, "Unknown lexer error code." } }; @@ -75,6 +82,7 @@ typedef struct cmLex_str cmChar_t* textBuf; // text buf used by cmLexSetFile() + unsigned attrFlags; // used to store the int and real suffix type flags } cmLex; @@ -148,7 +156,7 @@ unsigned _cmLexRealMatcher( cmLex* p, const cmChar_t* cp, unsigned cn, const cm unsigned i = 0; unsigned n = 0; // decimal point counter unsigned d = 0; // digit counter - bool fl = false; // true if this real includes an exponent + bool fl = false; // expo flag for(; i0 && i 0; + fl = e > 0; } - return i>1 && (n==1 || fl) ? i : 0; + // if at least one digit was found + if( d>0 ) + { + // Note that this path allows a string w/o a decimal pt to trigger a match. + + if(iattrFlags = cmSetFlag(p->attrFlags,kRealFloatLexFl); + ++i; + break; + } + + } + + // match w/o suffix return + if( d>0 && (fl || n==1 || cmIsFlag(p->attrFlags,kRealFloatLexFl)) ) + return i; + } + + return 0; // no-match return } unsigned _cmLexIntMatcher( cmLex* p, const cmChar_t* cp, unsigned cn, const cmChar_t* keyStr ) { unsigned i = 0; bool signFl = false; + for(; iattrFlags = cmSetFlag(p->attrFlags,kIntUnsignedLexFl); + ++i; + } + break; + + default: + break; + } + } + + return i; } unsigned _cmLexHexMatcher( cmLex* p, const cmChar_t* cp, unsigned cn, const cmChar_t* keyStr ) @@ -387,23 +449,6 @@ cmLexH cmLexInit( const cmChar_t* cp, unsigned cn, unsigned flags, cmRpt_t* rpt _cmLexSetTextBuffer( p, cp, cn ); - /* - p->cp = (cn==0) ? NULL : cp; - p->cn = (cp==NULL) ? 0 : cn; - - p->ci = 0; - - - p->curTokenId = kErrorLexTId; - p->curTokenCharIdx = cmInvalidIdx; - p->curTokenCharCnt = 0; - - p->curLine = 0; - p->curCol = 0; - p->nextLine = 0; - p->nextCol = 0; - */ - int init_mfn = 10; p->mfp = cmMemAllocZ( cmLexMatcher, init_mfn ); p->mfn = init_mfn; @@ -537,70 +582,6 @@ cmRC_t cmLexSetFile( cmLexH h, const cmChar_t* fn ) return rc; } -/* -cmRC_t cmLexSetFile( cmLexH h, const cmChar_t* fn ) -{ - cmRC_t rc = kOkLexRC; - FILE* fp = NULL; - cmLex* p = _cmLexHandleToPtr(h); - unsigned n = 0; - - assert( fn != NULL && p != NULL ); - - // open the file - if((fp = fopen(fn,"rb")) == NULL ) - return _cmLexError(p,kFileOpenErrLexRC,"Unable to open the file:'%s'.",fn); - - // seek to the end - if( fseek(fp,0,SEEK_END) != 0 ) - { - rc= _cmLexError(p,kFileSeekErrLexRC,"Unable to seek to the end of '%s'.",fn); - goto errLabel; - } - - // get the length of the file - if( (n=ftell(fp)) == 0 ) - { - rc = _cmLexError(p,kFileOpenErrLexRC,"The file '%s' appears to be empty.",fn); - goto errLabel; - } - - // rewind the file - if( fseek(fp,0,SEEK_SET) != 0 ) - { - rc = _cmLexError(p,kFileSeekErrLexRC,"Unable to seek to the beginning of '%s'.",fn); - goto errLabel; - } - - // allocate the text buffer - if((p->textBuf = cmMemResizeZ( char, p->textBuf, n+1)) == NULL ) - { - rc = _cmLexError(p,kMemAllocErrLexRC,"Unable to allocate the text file buffer for:'%s'.",fn); - goto errLabel; - } - - // read the file into the text buffer - if( fread(p->textBuf,n,1,fp) != 1 ) - { - rc = _cmLexError(p,kFileReadErrLexRC,"File read failed on:'%s'.",fn); - goto errLabel; - } - - if((rc = _cmLexSetTextBuffer( p, p->textBuf, n )) != kOkLexRC ) - goto errLabel; - - errLabel: - - // close the file - if( fclose(fp) != 0 ) - { - rc = _cmLexError(p,kFileCloseErrLexRC,"File close failed on:'%s'.",fn); - goto errLabel; - } - - return rc; -} -*/ cmLexMatcher* _cmLexFindUserToken( cmLex* p, unsigned id, const cmChar_t* tokenStr ) { @@ -689,9 +670,9 @@ unsigned cmLexGetNextToken( cmLexH h ) p->curTokenId = kErrorLexTId; p->curTokenCharIdx = cmInvalidIdx; p->curTokenCharCnt = 0; + p->attrFlags = 0; - - // try each mater + // try each matcher for(; mimfi; ++mi) if( p->mfp[mi].enableFl ) { @@ -701,6 +682,7 @@ unsigned cmLexGetNextToken( cmLexH h ) else charCnt = p->mfp[mi].userPtr( p->cp + p->ci, p->cn - p->ci); + // notice if the matcher set the error code if( cmErrLastRC(&p->err) != kOkLexRC ) return kErrorLexTId; @@ -823,6 +805,19 @@ float cmLexTokenFloat( cmLexH h ) double cmLexTokenDouble( cmLexH h ) { return strtod( cmLexTokenText(h),NULL ); } + +bool cmLexTokenIsUnsigned( cmLexH h ) +{ + cmLex* p = _cmLexHandleToPtr(h); + return p->curTokenId == kIntLexTId && cmIsFlag(p->attrFlags,kIntUnsignedLexFl); +} + +bool cmLexTokenIsSinglePrecision( cmLexH h ) +{ + cmLex* p = _cmLexHandleToPtr(h); + return p->curTokenId == kRealLexTId && cmIsFlag(p->attrFlags,kRealFloatLexFl); +} + unsigned cmLexCurrentLineNumber( cmLexH h ) { cmLex* p = _cmLexHandleToPtr(h); diff --git a/cmLex.h b/cmLex.h index fcd80aa..5eed6aa 100644 --- a/cmLex.h +++ b/cmLex.h @@ -50,7 +50,8 @@ enum kMemAllocErrLexRC, //< 10 An attempted memory allocation failed kEofRC, //< 11 The end of the input text was encountered (this is a normal condition not an error) kInvalidLexTIdLexRC, //< 12 An invalid lex token id was encountered. - kInvalidLexRC //< 13 Sentinal value. + kSignErrorLexRC, //< 13 An signed integer has a 'u' or 'U' suffix." + kInvalidLexRC //< 1r Sentinal value. }; @@ -119,15 +120,23 @@ unsigned cmLexTokenCharCount( cmLexH h ); // Return the value of the current token as an integer. int cmLexTokenInt( cmLexH h ); -// Return the value of the current token as an integer. +// Return the value of the current token as an unsigned integer. unsigned cmLexTokenUInt( cmLexH h ); -// Return the value of the current token as an integer. +// Return the value of the current token as a float. float cmLexTokenFloat( cmLexH h ); // Return the value of the current token as a double. double cmLexTokenDouble( cmLexH h ); +// Return true if the current token is an int and it was suffixed +// with 'u' to indicate that it is unsigned. +bool cmLexTokenIsUnsigned( cmLexH h ); + +// Return true if the current token is a real and it was suffexed +// with 'f' to indicate that it is a single precision float. +bool cmLexTokenIsSinglePrecision( cmLexH h ); + // Return the line number associated with the current token unsigned cmLexCurrentLineNumber( cmLexH h ); diff --git a/cmMidiFile.h b/cmMidiFile.h index 4f7463a..15a61dd 100644 --- a/cmMidiFile.h +++ b/cmMidiFile.h @@ -64,7 +64,7 @@ extern "C" { { unsigned uid; // uid's are unique among all msg's in the file unsigned dtick; // delta ticks - unsigned atick; + unsigned atick; // accumulated ticks cmMidiByte_t status; // ch msg's have the channel value removed (it is stored in u.chMsgPtr->ch) cmMidiByte_t metaId; // unsigned short trkIdx; // diff --git a/cmProc4.c b/cmProc4.c index fb48fba..9f977dd 100644 --- a/cmProc4.c +++ b/cmProc4.c @@ -4135,3 +4135,356 @@ cmRC_t cmScModulatorDump( cmScModulator* p ) return rc; } + +//======================================================================================================================= +cmRecdPlay* cmRecdPlayAlloc( cmCtx* c, cmRecdPlay* p, double srate, unsigned fragCnt, unsigned chCnt, double initFragSecs, double maxLaSecs, double curLaSecs ) +{ + cmRecdPlay* op = cmObjAlloc(cmRecdPlay,c,p); + + if( cmRecdPlayInit(op,srate,fragCnt,chCnt,initFragSecs,maxLaSecs,curLaSecs) != cmOkRC ) + cmRecdPlayFree(&op); + + return op; +} + +cmRC_t cmRecdPlayFree( cmRecdPlay** pp ) +{ + cmRC_t rc = cmOkRC; + if( pp==NULL || *pp==NULL ) + return rc; + + cmRecdPlay* p = *pp; + if((rc = cmRecdPlayFinal(p)) != cmOkRC ) + return rc; + + cmObjFree(pp); + return rc; + +} + +cmRC_t cmRecdPlayInit( cmRecdPlay* p, double srate, unsigned fragCnt, unsigned chCnt, double initFragSecs, double maxLaSecs, double curLaSecs ) +{ + cmRC_t rc; + unsigned i; + + if( curLaSecs > maxLaSecs ) + return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The initial look-ahead time %f is greater than the maximum look-ahead time %f.",curLaSecs,maxLaSecs); + + if((rc = cmRecdPlayFinal(p)) != cmOkRC ) + return rc; + + if( chCnt == 0 ) + return cmOkRC; + + p->frags = cmMemAllocZ(cmRecdPlayFrag,fragCnt); + p->fragCnt = fragCnt; + p->srate = srate; + p->chCnt = chCnt; + p->initFragSecs = initFragSecs; + p->maxLaSmpCnt = floor(maxLaSecs*srate); + p->curLaSmpCnt = floor(curLaSecs*srate); + p->laChs = cmMemAllocZ(cmSample_t*,chCnt); + p->laSmpIdx = 0; + + for(i=0; ilaChs[i] = cmMemAllocZ(cmSample_t,p->maxLaSmpCnt); + + return rc; +} + +cmRC_t cmRecdPlayFinal( cmRecdPlay* p ) +{ + unsigned i,j; + // free the fragments + for(i=0; ifragCnt; ++i) + { + for(j=0; jchCnt; ++j) + cmMemFree(p->frags[i].chArray[j]); + + cmMemFree(p->frags[i].chArray); + } + + // free the look-ahead buffers + for(i=0; ichCnt; ++i) + cmMemFree(p->laChs[i]); + + cmMemPtrFree(&p->laChs); + cmMemPtrFree(&p->frags); + p->fragCnt = 0; + p->chCnt = 0; + p->rlist = NULL; + p->plist = NULL; + return cmOkRC; +} + +cmRC_t cmRecdPlayRegisterFrag( cmRecdPlay* p, unsigned fragIdx, unsigned labelSymId ) +{ + assert( fragIdx < p->fragCnt ); + + unsigned i; + + p->frags[ fragIdx ].labelSymId = labelSymId; + + p->frags[ fragIdx ].chArray = cmMemResizeZ(cmSample_t*,p->frags[fragIdx].chArray,p->chCnt); + + for(i=0; ichCnt; ++i) + { + + p->frags[ fragIdx ].allocCnt = floor(p->initFragSecs * p->srate); + p->frags[ fragIdx ].chArray[i] = cmMemResizeZ(cmSample_t,p->frags[ fragIdx ].chArray[i],p->frags[fragIdx].allocCnt); + } + + return cmOkRC; +} + +cmRC_t cmRecdPlayRewind( cmRecdPlay* p ) +{ + unsigned i; + + p->laSmpIdx = 0; + + while( p->plist != NULL ) + cmRecdPlayEndPlay(p,p->plist->labelSymId); + + while( p->rlist != NULL ) + cmRecdPlayEndRecord(p,p->plist->labelSymId); + + for(i=0; ifragCnt; ++i) + p->frags[i].playIdx = 0; + + return cmOkRC; +} + + +cmRC_t cmRecdPlayBeginRecord( cmRecdPlay* p, unsigned labelSymId ) +{ + unsigned i; + + for(i=0; ifragCnt; ++i) + if( p->frags[i].labelSymId == labelSymId ) + { + // if the frag is not already on the recd list + if( p->frags[i].rlink == NULL ) + { + p->frags[i].recdIdx = 0; + p->frags[i].playIdx = 0; + p->frags[i].rlink = p->rlist; + p->rlist = p->frags + i; + + // handle LA buf longer than frag buf. + int cpyCnt = cmMin(p->curLaSmpCnt,p->frags[i].allocCnt); + + // go backwards in LA buf from newest sample to find init src offset + int srcOffs = p->laSmpIdx - cpyCnt; + + // if the src is before the first sample in the LA buf then wrap to end of buf + if( srcOffs < 0 ) + srcOffs += p->maxLaSmpCnt; + + assert( 0 <= srcOffs && srcOffs < p->maxLaSmpCnt ); + + // cnt of samples to copy from LA buf (limited by end of LA buf) + int n0 = cmMin(cpyCnt,p->maxLaSmpCnt - srcOffs); + + // if necessary wrap to begin of LA buf for remaining samples + int n1 = cpyCnt>n0 ? n1 = cpyCnt-n0 : 0; + int j; + + assert(n0+n1 == cpyCnt ); + + for(j=0; jchCnt; ++j) + cmVOS_Copy(p->frags[i].chArray[j],n0,p->laChs[j]+srcOffs); + + if( n1 > 0 ) + { + for(j=0; jchCnt; ++j) + cmVOS_Copy(p->frags[i].chArray[j]+n0,n1,p->laChs[j]); + } + + p->frags[i].recdIdx = cpyCnt; + + } + + return cmOkRC; + } + + return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The fragment label symbol id '%i' not found for 'begin record'.",labelSymId); +} + +cmRC_t cmRecdPlayEndRecord( cmRecdPlay* p, unsigned labelSymId ) +{ + cmRecdPlayFrag* fp = p->rlist; + cmRecdPlayFrag* pp = NULL; + + for(; fp != NULL; fp=fp->rlink ) + { + if( fp->labelSymId == labelSymId ) + { + if( pp == NULL ) + p->rlist = fp->rlink; + else + pp->rlink = fp->rlink; + + fp->rlink = NULL; + + return cmOkRC; + } + + pp = fp; + } + + return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The fragment label symbol id '%i' not found for 'end record'.",labelSymId); +} + +cmRC_t cmRecdPlayBeginPlay( cmRecdPlay* p, unsigned labelSymId ) +{ + unsigned i; + + for(i=0; ifragCnt; ++i) + if( p->frags[i].labelSymId == labelSymId ) + { + // if the frag is not already on the play list + if( p->frags[i].plink == NULL ) + { + p->frags[i].playIdx = 0; + p->frags[i].fadeSmpIdx = 0; + p->frags[i].fadeDbPerSec = 0.0; + p->frags[i].plink = p->plist; + p->plist = p->frags + i; + } + + return cmOkRC; + } + + return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The fragment label symbol id '%i' not found for 'begin play'.",labelSymId); + +} + +cmRC_t cmRecdPlayEndPlay( cmRecdPlay* p, unsigned labelSymId ) +{ + cmRecdPlayFrag* fp = p->plist; + cmRecdPlayFrag* pp = NULL; + + for(; fp != NULL; fp=fp->plink ) + { + if( fp->labelSymId == labelSymId ) + { + if( pp == NULL ) + p->plist = fp->plink; + else + pp->plink = fp->plink; + + fp->plink = NULL; + + return cmOkRC; + } + + pp = fp; + } + + return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The fragment label symbol id '%i' not found for 'end play'.",labelSymId); +} + +cmRC_t cmRecdPlayBeginFade( cmRecdPlay* p, unsigned labelSymId, double fadeDbPerSec ) +{ + cmRecdPlayFrag* fp = p->plist; + + for(; fp != NULL; fp=fp->plink ) + if( fp->labelSymId == labelSymId ) + { + fp->fadeDbPerSec = -fabs(fadeDbPerSec); + return cmOkRC; + } + + return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The fragment label symbol id '%i' not found for 'fade begin'.",labelSymId); +} + + +cmRC_t cmRecdPlayExec( cmRecdPlay* p, const cmSample_t** iChs, cmSample_t** oChs, unsigned chCnt, unsigned smpCnt ) +{ + unsigned i; + + chCnt = cmMin(chCnt, p->chCnt); + + //------------------------------------------------------------------- + // copy incoming audio into the look-head buffers + // + + // if the number of incoming samples is longer than the look-head buffer + // then copy exactly maxLaSmpCnt samples from the end of the incoming sample + // buffer to the look-ahead buffer. + unsigned srcOffs = 0; + unsigned srcSmpCnt = smpCnt; + if( srcSmpCnt > p->maxLaSmpCnt ) + { + // advance incoming sample buffer so that there are maxLaSmpCnt samples remaining + srcOffs = smpCnt-p->maxLaSmpCnt; + srcSmpCnt = p->maxLaSmpCnt; // decrease the total samples to copy + } + + // count of samples from cur posn to end of the LA buffer. + unsigned n0 = cmMin(srcSmpCnt, p->maxLaSmpCnt - p->laSmpIdx ); + + // count of samples past the end of the LA buffer to be wrapped into begin of buffer + unsigned n1 = srcSmpCnt>n0 ? srcSmpCnt-n0 : 0; + + assert(n0+n1 == srcSmpCnt); + + // copy first block to end of LA buffer + for(i=0; ilaChs[i]+p->laSmpIdx,n0,iChs[i] + srcOffs); + + p->laSmpIdx += n0; + + if( n1!=0) + { + // copy second block to begin of LA buffer + for(i=0; ilaChs[i],n1,iChs[i] + srcOffs + n0); + + p->laSmpIdx = n1; + + } + + //------------------------------------------------------------------- + // copy incoming audio into the active record buffers + // + cmRecdPlayFrag* fp = p->rlist; + + for(; fp!=NULL; fp=fp->rlink) + { + assert( fp->recdIdx <= fp->allocCnt); + unsigned n = cmMin(fp->allocCnt - fp->recdIdx,smpCnt); + unsigned i; + for(i=0; ichCnt; ++i) + { + cmVOS_Copy(fp->chArray[i] + fp->recdIdx, n, iChs[i] ); + fp->recdIdx += n; + } + } + + //------------------------------------------------------------------- + // copy outgoing audio out of the active play buffers + // + fp = p->plist; + for(; fp!=NULL; fp=fp->rlink) + { + assert( fp->playIdx <= fp->recdIdx); + + double gain = pow(10.0,((fp->fadeSmpIdx / p->srate) * fp->fadeDbPerSec)/20.0); + unsigned n = cmMin(fp->recdIdx - fp->playIdx,smpCnt); + unsigned i; + + for(i=0; ichCnt; ++i) + { + cmVOS_MultVVS(oChs[i],n,fp->chArray[i] + fp->playIdx,gain); + fp->playIdx += n; + } + + // if a fade rate has been set then advance the fade phase + if(fp->fadeDbPerSec!=0.0) + fp->fadeSmpIdx += smpCnt; + } + + return cmOkRC; +} diff --git a/cmProc4.h b/cmProc4.h index 0dde90a..8ad104e 100644 --- a/cmProc4.h +++ b/cmProc4.h @@ -626,6 +626,55 @@ extern "C" { cmRC_t cmScModulatorExec( cmScModulator* p, unsigned scLocIdx ); cmRC_t cmScModulatorDump( cmScModulator* p ); + //======================================================================================================================= + + typedef struct cmRecdPlayFrag_str + { + unsigned labelSymId; // this fragments label + cmSample_t** chArray; // record buffer chArray[cmRecdPlay.chCnt][allocCnt] + unsigned allocCnt; // count of samples allocated to each channel + unsigned playIdx; // index of next sample to play + unsigned recdIdx; // index of next sample to receieve audio (count of full samples) + double fadeDbPerSec; // fade rate in dB per second + unsigned fadeSmpIdx; + struct cmRecdPlayFrag_str* rlink; // cmRecdPlay.rlist link + struct cmRecdPlayFrag_str* plink; // cmRecdPlay.plist link + } cmRecdPlayFrag; + + typedef struct + { + cmObj obj; + cmRecdPlayFrag* frags; // frags[fragCnt] fragment array + unsigned fragCnt; // count of fragments + double srate; // system sample rate + unsigned chCnt; // count of input and output audio channels + double initFragSecs; // size initial memory allocated to each frag in seconds + unsigned maxLaSmpCnt; // samples allocated to each channel of the look-ahead buffers. + unsigned curLaSmpCnt; // current look-ahead time in samples (curLaSmpCnt<=maxLaSmpCnt) + cmSample_t** laChs; // laChs[chCnt][maxLaSmpCnt] - look-ahead buffers + int laSmpIdx; // next look-ahead buffer index to receive a sample + cmRecdPlayFrag* plist; // currently playing frags + cmRecdPlayFrag* rlist; // currently recording frags + } cmRecdPlay; + + + cmRecdPlay* cmRecdPlayAlloc( cmCtx* c, cmRecdPlay* p, double srate, unsigned fragCnt, unsigned chCnt, double initFragSecs, double maxLaSecs, double curLaSecs ); + cmRC_t cmRecdPlayFree( cmRecdPlay** pp ); + cmRC_t cmRecdPlayInit( cmRecdPlay* p, double srate, unsigned flagCnt, unsigned chCnt, double initFragSecs, double maxLaSecs, double curLaSecs ); + cmRC_t cmRecdPlayFinal( cmRecdPlay* p ); + + cmRC_t cmRecdPlayRegisterFrag( cmRecdPlay* p, unsigned fragIdx, unsigned labelSymId ); + + cmRC_t cmRecdPlayRewind( cmRecdPlay* p ); + cmRC_t cmRecdPlayBeginRecord( cmRecdPlay* p, unsigned labelSymId ); + cmRC_t cmRecdPlayEndRecord( cmRecdPlay* p, unsigned labelSymId ); + cmRC_t cmRecdPlayBeginPlay( cmRecdPlay* p, unsigned labelSymId ); + cmRC_t cmRecdPlayEndPlay( cmRecdPlay* p, unsigned labelSymId ); + + cmRC_t cmRecdPlayBeginFade( cmRecdPlay* p, unsigned labelSymId, double fadeDbPerSec ); + + cmRC_t cmRecdPlayExec( cmRecdPlay* p, const cmSample_t** iChs, cmSample_t** oChs, unsigned chCnt, unsigned smpCnt ); + #ifdef __cplusplus } #endif diff --git a/cmStack.h b/cmStack.h index 63d06db..189acc2 100644 --- a/cmStack.h +++ b/cmStack.h @@ -42,12 +42,15 @@ extern "C" { const void* cmStackTop( cmStackH_t h ); // Set the value of 'dataEleCnt' elements on the stack. + // The top element is at index cmStackCount() - 1. cmStRC_t cmStackSet( cmStackH_t h, unsigned index, const void* data, unsigned dataEleCnt ); // Copy 'dataEleCnt' elements into the buffer pointed to by 'data'. + // The top element is at index cmStackCount() - 1. cmStRC_t cmStackGetN( cmStackH_t h, unsigned index, void* data, unsigned dataEleCnt ); // Return a pointer to a single element on the stack. + // The top element is at index cmStackCount() - 1. const void* cmStackGet( cmStackH_t h, unsigned index ); // Convert the internal representation of the stack to a linear array and return diff --git a/dsp/cmDspBuiltIn.c b/dsp/cmDspBuiltIn.c index d6642f2..90e9540 100644 --- a/dsp/cmDspBuiltIn.c +++ b/dsp/cmDspBuiltIn.c @@ -5418,6 +5418,7 @@ cmDspClassConsFunc_t _cmDspClassBuiltInArray[] = cmActiveMeasClassCons, cmAmSyncClassCons, cmNanoMapClassCons, + cmRecdPlayClassCons, NULL, }; diff --git a/dsp/cmDspKr.c b/dsp/cmDspKr.c index f260354..a19bb2f 100644 --- a/dsp/cmDspKr.c +++ b/dsp/cmDspKr.c @@ -572,7 +572,7 @@ cmDspRC_t _cmDspScoreReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* } if((tlFn = cmDspStrcz(inst, kFnScId )) != NULL ) - if( cmScoreInitialize(ctx->cmCtx, &p->scH, tlFn, cmDspSampleRate(ctx), dynRefArray, dynRefCnt, _cmDspScoreCb, p, cmSymTblNullHandle ) != kOkTlRC ) + if( cmScoreInitialize(ctx->cmCtx, &p->scH, tlFn, cmDspSampleRate(ctx), dynRefArray, dynRefCnt, _cmDspScoreCb, p, ctx->stH ) != kOkTlRC ) rc = cmErrMsg(&inst->classPtr->err, kInstResetFailDspRC, "Score file open failed."); errLabel: @@ -2264,3 +2264,262 @@ struct cmDspClass_str* cmNanoMapClassCons( cmDspCtx_t* ctx ) return &_cmNanoMapDC; } + +//========================================================================================================================================== +enum +{ + kChCntPrId, + kFnPrId, + kSecsPrId, + kMaxLaSecsPrId, + kCurLaSecsPrId, + kFadeRatePrId, + kScLocIdxPrId, + kCmdPrId, + kInAudioBasePrId +}; + +cmDspClass_t _cmRecdPlayDC; + +typedef struct +{ + cmDspInst_t inst; + cmRecdPlay* rcdply; + cmScH_t scH; + unsigned onSymId; + unsigned offSymId; + unsigned audioOutBaseId; + unsigned chCnt; + unsigned scLocIdx; +} cmDspRecdPlay_t; + +cmDspRC_t _cmDspRecdPlayOpenScore( cmDspCtx_t* ctx, cmDspInst_t* inst ) +{ + cmDspRC_t rc =kOkDspRC; + const cmChar_t* fn; + + cmDspRecdPlay_t* p = (cmDspRecdPlay_t*)inst; + + p->scLocIdx = 0; + + + if((fn = cmDspStrcz(inst,kFnPrId)) == NULL || strlen(fn)==0 ) + return cmErrMsg(&inst->classPtr->err, kInvalidArgDspRC, "No score file name supplied."); + + if( cmScoreInitialize(ctx->cmCtx, &p->scH, fn, cmDspSampleRate(ctx), NULL, 0, NULL, NULL, ctx->stH ) != kOkScRC ) + return cmErrMsg(&inst->classPtr->err, kSubSysFailDspRC, "Unable to open the score '%s'.",fn); + + if( cmScoreIsValid(p->scH) ) + { + unsigned i; + unsigned markerCnt = cmScoreMarkerLabelCount(p->scH); + double initFragSecs = cmDspDouble(inst,kSecsPrId); + double maxLaSecs = cmDspDouble(inst,kMaxLaSecsPrId); + double curLaSecs = cmDspDouble(inst,kCurLaSecsPrId); + + if((p->rcdply = cmRecdPlayAlloc(ctx->cmProcCtx, NULL, cmDspSampleRate(ctx), markerCnt, p->chCnt, initFragSecs, maxLaSecs, curLaSecs)) == NULL) + return cmErrMsg(&inst->classPtr->err,kSubSysFailDspRC,"Unable to create the internal recorder-player object."); + + for(i=0; ircdply,i, cmScoreMarkerLabelSymbolId(p->scH,i )); + + } + + return rc; +} + + +cmDspInst_t* _cmDspRecdPlayAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl ) +{ + + if( va_cnt < 1 ) + { + cmDspClassErr(ctx,classPtr,kVarArgParseFailDspRC,"The 'RecdPlay' constructor must have a count of input ports."); + return NULL; + } + + va_list vl1; + va_copy(vl1,vl); + + int chCnt = va_arg(vl,int); + unsigned audioOutBase = kInAudioBasePrId + chCnt; + + cmDspRecdPlay_t* p = cmDspInstAllocV(cmDspRecdPlay_t,ctx,classPtr,instSymId,id,storeSymId,va_cnt,vl1, + 1, "chs", kChCntPrId, 0,0, kUIntDsvFl | kReqArgDsvFl, "channel count.", + 1, "fn", kFnPrId, 0,0, kInDsvFl | kStrzDsvFl | kReqArgDsvFl, "Score file." , + 1, "secs", kSecsPrId, 0,0, kInDsvFl | kDoubleDsvFl | kReqArgDsvFl, "Initial fragment allocation in seconds.", + 1, "maxla", kMaxLaSecsPrId, 0,0, kInDsvFl | kDoubleDsvFl, "Maximum look-ahead buffer in seconds.", + 1, "curla", kCurLaSecsPrId, 0,0, kInDsvFl | kDoubleDsvFl, "Current look-head buffer in seconds.", + 1, "frate", kFadeRatePrId, 0,0, kInDsvFl | kDoubleDsvFl, "Fade rate in dB per second.", + 1, "index", kScLocIdxPrId, 0,0, kInDsvFl | kUIntDsvFl, "Score follower location index.", + 1, "cmd", kCmdPrId, 0,0, kInDsvFl | kSymDsvFl, "on=reset off=stop.", + chCnt, "in", kInAudioBasePrId,0,1, kInDsvFl | kAudioBufDsvFl, "Audio input", + chCnt, "out", audioOutBase, 0,1, kOutDsvFl | kAudioBufDsvFl, "Audio output", + 0 ); + + va_end(vl1); + + p->onSymId = cmSymTblId(ctx->stH,"on"); + p->offSymId = cmSymTblId(ctx->stH,"off"); + p->audioOutBaseId = audioOutBase; + p->chCnt = chCnt; + p->scLocIdx = 0; + + cmDspSetDefaultDouble(ctx,&p->inst, kSecsPrId, 0, 10.0 ); + cmDspSetDefaultDouble(ctx,&p->inst, kMaxLaSecsPrId,0, 2.0); + cmDspSetDefaultDouble(ctx,&p->inst, kCurLaSecsPrId,0, 0.5); + cmDspSetDefaultDouble(ctx,&p->inst, kFadeRatePrId, 0, 1.0); + + return &p->inst; +} + +cmDspRC_t _cmDspRecdPlayFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt ) +{ + cmDspRC_t rc = kOkDspRC; + cmDspRecdPlay_t* p = (cmDspRecdPlay_t*)inst; + + cmRecdPlayFree(&p->rcdply); + + cmScoreFinalize(&p->scH); + return rc; +} + +cmDspRC_t _cmDspRecdPlayReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt ) +{ + cmDspApplyAllDefaults(ctx,inst); + + return _cmDspRecdPlayOpenScore(ctx,inst); +} + +cmDspRC_t _cmDspRecdPlayExec(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt ) +{ + cmDspRC_t rc = kOkDspRC; + + cmDspRecdPlay_t* p = (cmDspRecdPlay_t*)inst; + + const cmSample_t* x[ p->chCnt ]; + cmSample_t* y[ p->chCnt ]; + unsigned n; + unsigned i; + unsigned actChCnt = 0; + + for(i=0; ichCnt; ++i) + { + if( i==0 ) + n = cmDspAudioBufSmpCount(ctx,inst,kInAudioBasePrId+i,0); + else + { assert( n == cmDspAudioBufSmpCount(ctx,inst,kInAudioBasePrId+i,0)); } + + x[i] = cmDspAudioBuf(ctx,inst,kInAudioBasePrId+i,0); + + if( x[i] != NULL ) + { + y[i] = cmDspAudioBuf(ctx,inst,p->audioOutBaseId+i,0); + + if( y[i] != NULL ) + { + assert( n == cmDspAudioBufSmpCount(ctx,inst,p->audioOutBaseId+i,0)); + + cmVOS_Zero(y[i],n); + + actChCnt += 1; + } + + } + } + + cmRecdPlayExec(p->rcdply,x,y,actChCnt,n); + + return rc; +} + +cmDspRC_t _cmDspRecdPlayRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt ) +{ + cmDspRecdPlay_t* p = (cmDspRecdPlay_t*)inst; + + cmDspSetEvent(ctx,inst,evt); + + switch( evt->dstVarId ) + { + case kCmdPrId: + if( cmDspSymbol(inst,kCmdPrId) == p->onSymId ) + { + printf("rewind\n"); + cmRecdPlayRewind(p->rcdply); + p->scLocIdx = 0; + } + else + if( cmDspSymbol(inst,kCmdPrId) == p->offSymId ) + { + } + + break; + + case kCurLaSecsPrId: + break; + + case kScLocIdxPrId: + { + unsigned endScLocIdx = cmDspUInt(inst,kScLocIdxPrId) ; + + for(; p->scLocIdx<=endScLocIdx; p->scLocIdx+=1) + { + cmScoreLoc_t* loc = cmScoreLoc(p->scH, p->scLocIdx ); + cmScoreMarker_t* mp = loc->markList; + + for(; mp!=NULL; mp=mp->link) + switch( mp->markTypeId ) + { + case kRecdBegScMId: + printf("recd-beg\n"); + cmRecdPlayBeginRecord(p->rcdply, mp->labelSymId ); + break; + + case kRecdEndScMId: + printf("recd-end\n"); + cmRecdPlayEndRecord(p->rcdply, mp->labelSymId ); + break; + + case kPlayBegScMId: + printf("play-beg\n"); + cmRecdPlayBeginPlay(p->rcdply, mp->labelSymId ); + break; + + case kPlayEndScMId: + printf("play-end\n"); + cmRecdPlayEndPlay(p->rcdply, mp->labelSymId ); + break; + + case kFadeScMId: + printf("fade-beg\n"); + cmRecdPlayBeginFade(p->rcdply, mp->labelSymId, cmDspDouble(inst,kFadeRatePrId) ); + break; + + default: + break; + } + } + + p->scLocIdx = endScLocIdx+1; + } + break; + } + + return kOkDspRC; +} + +struct cmDspClass_str* cmRecdPlayClassCons( cmDspCtx_t* ctx ) +{ + cmDspClassSetup(&_cmRecdPlayDC,ctx,"RecdPlay", + NULL, + _cmDspRecdPlayAlloc, + _cmDspRecdPlayFree, + _cmDspRecdPlayReset, + _cmDspRecdPlayExec, + _cmDspRecdPlayRecv, + NULL, + NULL, + "Score controlled live recorder/player"); + + return &_cmRecdPlayDC; +} diff --git a/dsp/cmDspKr.h b/dsp/cmDspKr.h index 454f85f..cbb0f04 100644 --- a/dsp/cmDspKr.h +++ b/dsp/cmDspKr.h @@ -16,6 +16,7 @@ extern "C" { struct cmDspClass_str* cmActiveMeasClassCons( cmDspCtx_t* ctx ); struct cmDspClass_str* cmAmSyncClassCons( cmDspCtx_t* ctx ); struct cmDspClass_str* cmNanoMapClassCons( cmDspCtx_t* ctx ); + struct cmDspClass_str* cmRecdPlayClassCons( cmDspCtx_t* ctx ); #ifdef __cplusplus } diff --git a/dsp/cmDspPgmKr.c b/dsp/cmDspPgmKr.c index 2ef0d82..7b2aa02 100644 --- a/dsp/cmDspPgmKr.c +++ b/dsp/cmDspPgmKr.c @@ -97,7 +97,10 @@ cmDspRC_t _cmDspSysPgm_TimeLine(cmDspSysH_t h, void** userPtrPtr ) double cmpWndMaxMs = 1000.0; double cmpWndMs = 200.0; - + double recdPlayInitAllocSecs = 10.0; + double recdPlayMaxLaSecs = 2.0; + double recdPlayCurLaSecs = 0.1; + double recdPlayFadeRateDbPerSec = 4.0; memset(&r,0,sizeof(r)); cmErrSetup(&err,&cmCtx->rpt,"Kr Timeline"); @@ -122,6 +125,7 @@ cmDspRC_t _cmDspSysPgm_TimeLine(cmDspSysH_t h, void** userPtrPtr ) cmDspInst_t* mop = cmDspSysAllocInst(h,"MidiOut", NULL, 2, r.midiDevice,r.midiOutPort); cmDspInst_t* sfp = cmDspSysAllocInst(h,"ScFol", NULL, 1, r.scFn ); cmDspInst_t* amp = cmDspSysAllocInst(h,"ActiveMeas", NULL, 1, 100 ); + cmDspInst_t* rpp = cmDspSysAllocInst(h,"RecdPlay", NULL, 4, 2, r.scFn, recdPlayInitAllocSecs, recdPlayMaxLaSecs, recdPlayCurLaSecs, recdPlayFadeRateDbPerSec ); cmDspInst_t* modp = cmDspSysAllocInst(h,"ScMod", NULL, 2, r.modFn, "m1" ); cmDspInst_t* asp = cmDspSysAllocInst(h,"AmSync", NULL, 0 ); @@ -173,14 +177,14 @@ cmDspRC_t _cmDspSysPgm_TimeLine(cmDspSysH_t h, void** userPtrPtr ) cmDspInst_t* kr00 = cmDspSysAllocInst(h, "Kr", NULL, 2, krWndSmpCnt, krHopFact ); cmDspInst_t* kr01 = cmDspSysAllocInst(h, "Kr", NULL, 2, krWndSmpCnt, krHopFact ); cmDspInst_t* fad0 = cmDspSysAllocInst(h, "Xfader", NULL, 3, xfadeChCnt, xfadeMs, xfadeInitFl ); - cmDspInst_t* mix0 = cmDspSysAllocInst(h, "AMix", NULL, 3, xfadeChCnt, mixGain, mixGain ); + cmDspInst_t* mix0 = cmDspSysAllocInst(h, "AMix", NULL, 4, xfadeChCnt+1, mixGain, mixGain, mixGain ); cmDspInst_t* cmp0 = cmDspSysAllocInst(h,"Compressor", NULL, 8, cmpBypassFl, cmpThreshDb, cmpRatio_num, cmpAtkMs, cmpRlsMs, cmpMakeup, cmpWndMs, cmpWndMaxMs ); cmDspInst_t* ao0p = cmDspSysAllocInst(h,"AudioOut", NULL, 1, 0 ); cmDspInst_t* kr10 = cmDspSysAllocInst(h, "Kr", NULL, 2, krWndSmpCnt, krHopFact ); cmDspInst_t* kr11 = cmDspSysAllocInst(h, "Kr", NULL, 2, krWndSmpCnt, krHopFact ); cmDspInst_t* fad1 = cmDspSysAllocInst(h, "Xfader", NULL, 3, xfadeChCnt, xfadeMs, xfadeInitFl ); - cmDspInst_t* mix1 = cmDspSysAllocInst(h, "AMix", NULL, 3, xfadeChCnt, mixGain, mixGain ); + cmDspInst_t* mix1 = cmDspSysAllocInst(h, "AMix", NULL, 4, xfadeChCnt+1, mixGain, mixGain, mixGain ); cmDspInst_t* cmp1 = cmDspSysAllocInst(h,"Compressor", NULL, 8, cmpBypassFl, cmpThreshDb, cmpRatio_num, cmpAtkMs, cmpRlsMs, cmpMakeup, cmpWndMs, cmpWndMaxMs ); cmDspInst_t* ao1p = cmDspSysAllocInst(h,"AudioOut", NULL, 1, 1 ); @@ -378,12 +382,14 @@ cmDspRC_t _cmDspSysPgm_TimeLine(cmDspSysH_t h, void** userPtrPtr ) cmDspSysConnectAudio(h, wtp, "out", au0Sw, "a-in-0" ); // wt -> sw cmDspSysConnectAudio(h, ai0p, "out", au0Sw, "a-in-1" ); // ain -> sw cmDspSysConnectAudio(h, ai0p, "out", mi0p, "in" ); + cmDspSysConnectAudio(h, au0Sw,"a-out", rpp, "in-0"); // sw -> rcdply cmDspSysConnectAudio(h, au0Sw,"a-out", kr00, "in" ); // sw -> kr cmDspSysConnectAudio(h, kr00, "out", fad0, "in-0"); // kr -> fad cmDspSysConnectAudio(h, fad0, "out-0", mix0, "in-0"); // fad -> mix cmDspSysConnectAudio(h, au0Sw,"a-out", kr01, "in" ); // sw -> kr cmDspSysConnectAudio(h, kr01, "out", fad0, "in-1"); // kr -> fad cmDspSysConnectAudio(h, fad0, "out-1", mix0, "in-1"); // fad -> mix + cmDspSysConnectAudio(h, rpp, "out-0", mix0, "in-2"); cmDspSysConnectAudio(h, mix0, "out", cmp0, "in"); // mix -> cmp cmDspSysConnectAudio(h, cmp0, "out", ao0p, "in" ); // cmp -> aout @@ -391,12 +397,14 @@ cmDspRC_t _cmDspSysPgm_TimeLine(cmDspSysH_t h, void** userPtrPtr ) cmDspSysConnectAudio(h, wtp, "out", au1Sw, "a-in-0" ); // wt -> kr cmDspSysConnectAudio(h, ai1p, "out", au1Sw, "a-in-1" ); cmDspSysConnectAudio(h, ai1p, "out", mi1p, "in" ); + cmDspSysConnectAudio(h, au1Sw,"a-out", rpp, "in-1"); // sw -> rcdply cmDspSysConnectAudio(h, au1Sw,"a-out", kr10, "in" ); cmDspSysConnectAudio(h, kr10, "out", fad1, "in-0"); cmDspSysConnectAudio(h, fad1, "out-0", mix1, "in-0"); cmDspSysConnectAudio(h, au1Sw,"a-out", kr11, "in" ); // wt -> kr cmDspSysConnectAudio(h, kr11, "out", fad1, "in-1"); cmDspSysConnectAudio(h, fad1, "out-1", mix1, "in-1"); + cmDspSysConnectAudio(h, rpp, "out-0", mix1, "in-2"); cmDspSysConnectAudio(h, mix1, "out", cmp1, "in"); cmDspSysConnectAudio(h, cmp1, "out", ao1p, "in" ); // comp -> aout @@ -437,6 +445,7 @@ cmDspRC_t _cmDspSysPgm_TimeLine(cmDspSysH_t h, void** userPtrPtr ) cmDspSysInstallCb(h, pts, "on", wtRt, "s-in", NULL ); cmDspSysInstallCb(h, wtRt,"s-out-0", wtp, "cmd", NULL ); cmDspSysInstallCb(h, pts, "on", modp, "cmd", NULL ); + cmDspSysInstallCb(h, pts, "on", rpp, "cmd", NULL ); cmDspSysInstallCb(h, onb, "sym", amCmd, "rewind",NULL ); cmDspSysInstallCb(h, onb, "out", achan0,"reset", NULL ); cmDspSysInstallCb(h, onb, "out", achan1,"reset", NULL ); @@ -493,7 +502,8 @@ cmDspRC_t _cmDspSysPgm_TimeLine(cmDspSysH_t h, void** userPtrPtr ) cmDspSysInstallCb(h, mip, "d0", sfp, "d0", NULL ); cmDspSysInstallCb(h, mip, "status", sfp, "status", NULL ); - // score follower to modulator and printers + // score follower to recd_play,modulator and printers + cmDspSysInstallCb(h, sfp, "out", rpp, "index", NULL ); cmDspSysInstallCb(h, sfp, "out", modp, "index", NULL ); cmDspSysInstallCb(h, sfp, "recent", prp, "in", NULL ); // report 'recent' but only act on 'max' loc index