//| Copyright: (C) 2020-2024 Kevin Larke //| License: GNU GPL version 3.0 or above. See the accompanying LICENSE file. #include "cwCommon.h" #include "cwLog.h" #include "cwCommonImpl.h" #include "cwTest.h" #include "cwMem.h" #include "cwText.h" #include "cwObject.h" #include "cwCsv.h" #include "cwFile.h" #include "cwFileSys.h" #include "cwGutimReg.h" namespace cw { namespace gutim { namespace reg { typedef struct reg_file_str { char* player_name; char* take_label; char* path; char* midi_fname; file_t r; } reg_file_t; typedef struct reg_str { reg_file_t* fileA; unsigned fileN; } reg_t; reg_t* _handleToPtr( handle_t h ) { return handleToPtr(h); } rc_t _destroy( reg_t* p ) { for(unsigned i=0; ifileN; ++i) { mem::release(p->fileA[i].player_name); mem::release(p->fileA[i].take_label); mem::release(p->fileA[i].path); mem::release(p->fileA[i].midi_fname); } mem::release(p->fileA); mem::release(p); return kOkRC; } } } } cw::rc_t cw::gutim::reg::create( handle_t& hRef, const char* fname ) { rc_t rc = kOkRC; csv::handle_t csvH; const char* colLabelA[] = {"player_name","take_label","session_number","take_number","beg_loc","end_loc","skip_score_follow_fl","path" }; unsigned colLabelN = sizeof(colLabelA)/sizeof(colLabelA[0]); unsigned lineAllocN = 0; filesys::pathPart_t* pathPart = nullptr; auto cmp_func = [](const reg_file_t& r0, const reg_file_t& r1) { int cmp = textCompare(r0.player_name,r1.player_name); if( cmp < 0 ) return true; if( cmp > 0 ) return false; if( r0.r.session_number < r1.r.session_number ) return true; if( r0.r.session_number > r1.r.session_number ) return false; if( r0.r.take_number < r1.r.take_number ) return true; if( r0.r.take_number > r1.r.take_number ) return false; return false; }; if((rc = destroy(hRef)) != kOkRC ) return rc; reg_t* p = mem::allocZ(); // open the CSV if((rc = create(csvH,fname,colLabelA,colLabelN)) != kOkRC ) { rc = cwLogError(rc,"GUTIM reg CSV file open failed on '%s'.",cwStringNullGuard(fname)); goto errLabel; } // parse the reg CSV fname pathPart = filesys::pathParts(fname); // get the count of lines in the CSV file if((rc = line_count(csvH,lineAllocN)) != kOkRC ) { rc = cwLogError(rc,"CSV line count failed."); goto errLabel; } // rewind CSV file if((rc = rewind(csvH)) != kOkRC ) { rc = cwLogError(rc,"GUTIM registry CSV '%s' rewind failed.",cwStringNullGuard(fname)); goto errLabel; } // verify that that the CSV is not tempy if( lineAllocN <= 1 ) { rc = cwLogError(kInvalidStateRC,"The GUTIM registry CSV '%s' is empty.",cwStringNullGuard(fname)); goto errLabel; } lineAllocN -= 1; // subtract one to account for column titles p->fileA = mem::allocZ(lineAllocN); // skip col. labels if((rc = next_line(csvH)) != kOkRC ) { rc = cwLogError(rc,"CSV line advance failed on first line."); goto errLabel; } for(unsigned i=0; ifileA[i]; if((rc = getv( csvH, "player_name", fr.r.player_name, "take_label", fr.r.take_label, "path", fr.r.path, "session_number", fr.r.session_number, "take_number", fr.r.take_number, "beg_loc", fr.r.beg_loc, "end_loc", fr.r.end_loc, "skip_score_follow_fl", fr.r.skip_score_follow_fl )) != kOkRC ) { rc = cwLogError(rc,"GUTIM registry CSV parse failed."); goto errLabel; } fr.player_name = mem::duplStr(fr.r.player_name); fr.r.player_name = fr.player_name; fr.take_label = mem::duplStr(fr.r.take_label); fr.r.take_label = fr.take_label; fr.path = mem::duplStr(fr.r.path); fr.r.path = fr.path; fr.midi_fname = filesys::makeFn(pathPart->dirStr, "midi", "mid", fr.r.path, nullptr ); fr.r.midi_fname = fr.midi_fname; p->fileN += 1; // advance the current CSV if((rc = next_line( csvH )) != kOkRC ) { if( rc == kEofRC ) { rc = kOkRC; break; } rc = cwLogError(rc,"CSV 'next line' failed on '%s'.",cwStringNullGuard(fname)); goto errLabel; } } std::sort(p->fileA,p->fileA+p->fileN,cmp_func); hRef.set(p); errLabel: if(rc != kOkRC ) _destroy(p); destroy(csvH); mem::release(pathPart); return rc; } cw::rc_t cw::gutim::reg::destroy( handle_t& hRef ) { rc_t rc = kOkRC; if( !hRef.isValid() ) return rc; reg_t* p = _handleToPtr(hRef); if((rc = _destroy(p)) != kOkRC ) { cwLogError(rc,"Gutim registry destroy failed."); goto errLabel; } hRef.clear(); errLabel: return rc; } unsigned cw::gutim::reg::file_count( handle_t h ) { reg_t* p = _handleToPtr(h); return p->fileN; } cw::gutim::reg::file_t cw::gutim::reg::file_record( handle_t h, unsigned file_idx ) { reg_t* p = _handleToPtr(h); return p->fileA[ file_idx ].r; } void cw::gutim::reg::report( handle_t h ) { reg_t* p = _handleToPtr(h); cwLogInfo("performer sess take b-loc e-loc skip path"); cwLogInfo("---------- ---- ---- ----- ----- ----- -------------------------------------------"); for(unsigned i=0; ifileN; ++i) { const reg_file_t& fr = p->fileA[i]; const file_t& r = fr.r; cwLogInfo("%10s %4i %4i %5i %5i %5s %s %s", r.player_name, r.session_number, r.take_number, r.beg_loc, r.end_loc, r.skip_score_follow_fl?"true":"false", r.path, r.midi_fname); } } cw::rc_t cw::gutim::reg::test( const object_t* cfg ) { const char* dir = nullptr; rc_t rc = kOkRC; handle_t h; if((rc = cfg->getv("dir",dir)) != kOkRC ) { rc = cwLogError(rc,"The arg. parse GUTIM registry test."); goto errLabel; } if((rc = create(h,dir)) != kOkRC ) { rc = cwLogError(rc,"The GUTIM registry create failed."); goto errLabel; } report(h); errLabel: destroy(h); return rc; }