/* ** This is free software; you can redistribute it and/or ** modify it under the terms of the GNU Library General Public License ** as published by the Free Software Foundation; either version 2 ** of the License, or (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU Library General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ******************************************************************************/ #include "ajax.h" AjPTable resourceDbMethods = NULL; static AjPStr resourceinReadLine = NULL; const char* resourceStatus[] = { "Supported", "Referenced", "Unavailable", "None", NULL }; const char* resourceDataFormat[] = { "Unknown", "HTML", "Text", "Text (EMBL)", "Text (fasta)", "Text (gff)", NULL }; const char* resourceTags[] = { "ID", "IDalt", "Acc", "Name", "Desc", "URL", "URLlink", "URLrest", "URLsoap", "Cat", "EDAMtpc", "EDAMdat", "EDAMid", "EDAMfmt", "Xref", "Query", "Example", "Contact", "Email", "CCxref", "CCmisc", "CCrest", "CCsoap", "Status", NULL }; static AjBool resourceinReadDrcat(AjPResourcein thys, AjPResource resource); /* @datastatic ResourcePInFormat ********************************************** ** ** Data input formats data structure ** ** @alias ResourceSInFormat ** @alias ResourceOInFormat ** ** @attr Name [const char*] Format name ** @attr Desc [const char*] Format description ** @attr Alias [AjBool] Name is an alias for an identical definition ** @attr Try [AjBool] If true, try for an unknown input. Duplicate names ** and read-anything formats are set false ** @attr Read [(AjBool*)] Input function, returns ajTrue on success ** @@ ******************************************************************************/ typedef struct ResourceSInFormat { const char *Name; const char *Desc; AjBool Alias; AjBool Try; AjBool (*Read) (AjPResourcein thys, AjPResource resource); } ResourceOInFormat; #define ResourcePInFormat ResourceOInFormat* static ResourceOInFormat resourceinFormatDef[] = { /* "Name", "Description" */ /* Alias, Try, */ /* ReadFunction */ {"unknown", "Unknown format", AJFALSE, AJFALSE, resourceinReadDrcat}, /* default to first format */ {"drcat", "Data resource catalogue format", AJFALSE, AJFALSE, resourceinReadDrcat}, {NULL, NULL, 0, 0, NULL} }; static ajuint resourceinReadFmt(AjPResourcein resourcein, AjPResource resource, ajuint format); static AjBool resourceinRead(AjPResourcein resourcein, AjPResource resource); static AjBool resourceinformatFind(const AjPStr format, ajint* iformat); static AjBool resourceinFormatSet(AjPResourcein resourcein, AjPResource resource); static AjBool resourceinListProcess(AjPResourcein resourcein, AjPResource resource, const AjPStr listfile); static void resourceinListNoComment(AjPStr* text); static void resourceinQryRestore(AjPResourcein resourcein, const AjPQueryList node); static void resourceinQrySave(AjPQueryList node, const AjPResourcein resourcein); static AjBool resourceDefine(AjPResource thys, AjPResourcein resourcein); static AjBool resourceinQryProcess(AjPResourcein resourcein, AjPResource resource); static AjBool resourceinQueryMatch(const AjPQuery thys, const AjPResource resource); /* @filesection ajresourceread ************************************************ ** ** @nam1rule aj Function belongs to the AJAX library. ** */ /* @datasection [AjPResourcein] Data resource input objects ******************* ** ** Function is for manipulating data input objects ** ** @nam2rule Resourcein ******************************************************************************/ /* @section Data input constructors ******************************************* ** ** All constructors return a new data input object by pointer. It ** is the responsibility of the user to first destroy any previous ** data input object. The target pointer does not need to be ** initialised to NULL, but it is good programming practice to do so ** anyway. ** ** @fdata [AjPResourcein] ** ** @nam3rule New Construct a new data input object ** @nam4rule Drcat Construct using a DRCAT identifier ** ** @argrule Drcat dbname [const AjPStr] DRCAT identifier ** @valrule * [AjPResourcein] New data input object ** ** @fcategory new ** ******************************************************************************/ /* @func ajResourceinNew ****************************************************** ** ** Creates a new data input object. ** ** @return [AjPResourcein] New data input object. ** @category new [AjPResourcein] Default constructor ** @@ ******************************************************************************/ AjPResourcein ajResourceinNew(void) { AjPResourcein pthis; AJNEW0(pthis); pthis->Input = ajTextinNewDatatype(AJDATATYPE_RESOURCE); pthis->ResourceData = NULL; return pthis; } /* @func ajResourceinNewDrcat ************************************************* ** ** Creates a new data input object with a resolved DRCAT query ** ** @param [r] dbname [const AjPStr] DRCAT identifier ** ** @return [AjPResourcein] New data input object. ** @category new [AjPResourcein] Default constructor ** @@ ******************************************************************************/ AjPResourcein ajResourceinNewDrcat(const AjPStr dbname) { AjPResourcein pthis; AjPQuery qry; AjPTextin textin; AjPTextAccess textaccess; AjBool dbstat; AJNEW0(pthis); pthis->Input = ajTextinNewDatatype(AJDATATYPE_RESOURCE); pthis->ResourceData = NULL; textin = pthis->Input; qry = textin->Query; ajStrAssignC(&qry->DbName, "drcat"); dbstat = ajNamDbData(qry, 0); if(!dbstat) ajDie("ajResourceinNewDrcat '%S' failed to find drcat", dbname); ajFmtPrintS(&textin->Qry, "drcat:%S", dbname); ajStrAssignC(&qry->Field, "id"); ajStrAssignS(&qry->QryString, dbname); ajQueryAddFieldOrS(qry, qry->Field, qry->QryString); ajStrAssignC(&qry->Field, "acc"); ajQueryAddFieldOrS(qry, qry->Field, qry->QryString); ajStrAssignC(&qry->Formatstr, "drcat"); ajStrAssignC(&textin->Formatstr, "drcat"); resourceinformatFind(textin->Formatstr, &textin->Format); ajStrAssignC(&qry->Method, "emboss"); dbstat = ajNamDbQuery(qry); if(!dbstat) ajDie("ajResourceinNewDrcat '%S' failed to set querytype", dbname); qry->TextAccess = ajCallTableGetS(textDbMethods,qry->Method); textaccess = qry->TextAccess; textaccess->Access(textin); return pthis; } /* @section data input destructors ******************************************** ** ** Destruction destroys all internal data structures and frees the ** memory allocated for the data input object. ** ** @fdata [AjPResourcein] ** ** @nam3rule Del Destructor ** ** @argrule Del pthis [AjPResourcein*] Data resource input object ** ** @valrule * [void] ** ** @fcategory delete ** ******************************************************************************/ /* @func ajResourceinDel ****************************************************** ** ** Deletes a data input object. ** ** @param [d] pthis [AjPResourcein*] Data resource input ** @return [void] ** @category delete [AjPResourcein] Default destructor ** @@ ******************************************************************************/ void ajResourceinDel(AjPResourcein* pthis) { AjPResourcein thys; if(!pthis) return; thys = *pthis; if(!thys) return; ajDebug("ajResourceinDel called qry:'%S'\n", thys->Input->Qry); ajTextinDel(&thys->Input); AJFREE(*pthis); return; } /* @section data input modifiers ********************************************** ** ** These functions use the contents of a data input object and ** update them. ** ** @fdata [AjPResourcein] ** ** @nam3rule Clear Clear all values ** @nam3rule Qry Reset using a query string ** @suffix C Character string input ** @suffix S String input ** ** @argrule * thys [AjPResourcein] Data resource input object ** @argrule C txt [const char*] Query text ** @argrule S str [const AjPStr] query string ** ** @valrule * [void] ** ** @fcategory modify ** ******************************************************************************/ /* @func ajResourceinClear **************************************************** ** ** Clears a data input object back to "as new" condition, except ** for the query list which must be preserved. ** ** @param [w] thys [AjPResourcein] Data resource input ** @return [void] ** @category modify [AjPResourcein] Resets ready for reuse. ** @@ ******************************************************************************/ void ajResourceinClear(AjPResourcein thys) { ajDebug("ajResourceinClear called\n"); if(!thys) return; ajTextinClear(thys->Input); thys->ResourceData = NULL; return; } /* @func ajResourceinQryC ***************************************************** ** ** Resets a data input object using a new Universal ** Query Address ** ** @param [u] thys [AjPResourcein] Data resource input object. ** @param [r] txt [const char*] Query ** @return [void] ** @@ ******************************************************************************/ void ajResourceinQryC(AjPResourcein thys, const char* txt) { ajResourceinClear(thys); ajStrAssignC(&thys->Input->Qry, txt); return; } /* @func ajResourceinQryS ***************************************************** ** ** Resets a data input object using a new Universal ** Query Address ** ** @param [u] thys [AjPResourcein] Data resource input object. ** @param [r] str [const AjPStr] Query ** @return [void] ** @@ ******************************************************************************/ void ajResourceinQryS(AjPResourcein thys, const AjPStr str) { if(!thys) return; ajResourceinClear(thys); ajStrAssignS(&thys->Input->Qry, str); return; } /* @section casts ************************************************************* ** ** Return values ** ** @fdata [AjPResourcein] ** ** @nam3rule Trace Write debugging output ** ** @argrule * thys [const AjPResourcein] Data resource input object ** ** @valrule * [void] ** ** @fcategory cast ** ******************************************************************************/ /* @func ajResourceinTrace **************************************************** ** ** Debug calls to trace the data in a data input object. ** ** @param [r] thys [const AjPResourcein] Data resource input object. ** @return [void] ** @@ ******************************************************************************/ void ajResourceinTrace(const AjPResourcein thys) { ajDebug("data input trace\n"); ajDebug("====================\n\n"); ajTextinTrace(thys->Input); if(thys->ResourceData) ajDebug( " ResourceData: exists\n"); return; } /* @section Data data inputs ********************************************** ** ** These functions read the wxyxdesc data provided by the first argument ** ** @fdata [AjPResourcein] ** ** @nam3rule Read Read data data ** ** @argrule Read resourcein [AjPResourcein] Data resource input object ** @argrule Read resource [AjPResource] Data resource data ** ** @valrule * [AjBool] true on success ** ** @fcategory input ** ******************************************************************************/ /* @func ajResourceinRead ***************************************************** ** ** If the file is not yet open, calls resourceinQryProcess to convert the query ** into an open file stream. ** ** Uses resourceinRead for the actual file reading. ** ** Returns the results in the AjPResource object. ** ** @param [u] resourcein [AjPResourcein] Data resource data input definitions ** @param [w] resource [AjPResource] Data resource data returned. ** @return [AjBool] ajTrue on success. ** @category input [AjPResource] Master data data input, ** calls specific functions for file access type ** and data data format. ** @@ ******************************************************************************/ AjBool ajResourceinRead(AjPResourcein resourcein, AjPResource resource) { AjBool ret = ajFalse; AjPQueryList node = NULL; AjBool listdata = ajFalse; if(resourcein->Input->Filebuff) { /* (a) if file still open, keep reading */ ret = resourceinRead(resourcein, resource); } else { /* (b) if we have a list, try the next query in the list */ if(ajListGetLength(resourcein->Input->List)) { listdata = ajTrue; ajListPop(resourcein->Input->List, (void**) &node); ajResourceinQryS(resourcein, node->Qry); resourceinQryRestore(resourcein, node); ajStrDel(&node->Qry); ajStrDel(&node->Formatstr); AJFREE(node); if(!resourceinQryProcess(resourcein, resource) && !ajListGetLength(resourcein->Input->List)) return ajFalse; ret = resourceinRead(resourcein, resource); } else { /* (c) Must be a query - decode it */ if(!resourceinQryProcess(resourcein, resource) && !ajListGetLength(resourcein->Input->List)) return ajFalse; if(ajListGetLength(resourcein->Input->List)) /* maybe a new list */ listdata = ajTrue; ret = resourceinRead(resourcein, resource); } } /* Now read whatever we got */ while(!ret && ajListGetLength(resourcein->Input->List)) { /* Failed, but we have a list still - keep trying it */ if(listdata) ajErr("Failed to read data data '%S'", resourcein->Input->Qry); listdata = ajTrue; ajListPop(resourcein->Input->List,(void**) &node); ajResourceinQryS(resourcein, node->Qry); resourceinQryRestore(resourcein, node); ajStrDel(&node->Qry); ajStrDel(&node->Formatstr); AJFREE(node); if(!resourceinQryProcess(resourcein, resource)) continue; ret = resourceinRead(resourcein, resource); } if(!ret) { if(listdata) ajErr("Failed to read data data '%S'", resourcein->Input->Qry); return ajFalse; } resourceDefine(resource, resourcein); return ajTrue; } /* @funcstatic resourceinQueryMatch ******************************************* ** ** Compares a data data item to a query and returns true if they match. ** ** @param [r] thys [const AjPQuery] query. ** @param [r] resource [const AjPResource] Data resource data. ** @return [AjBool] ajTrue if the data data matches the query. ** @@ ******************************************************************************/ static AjBool resourceinQueryMatch(const AjPQuery thys, const AjPResource resource) { AjBool tested = ajFalse; AjIList iterfield = NULL; AjPQueryField field = NULL; AjBool ok = ajFalse; ajDebug("resourceinQueryMatch '%S' fields: %u Case %B Done %B\n", resource->Id, ajListGetLength(thys->QueryFields), thys->CaseId, thys->QryDone); if(!thys) /* no query to test, that's fine */ return ajTrue; if(thys->QryDone) /* do we need to test here? */ return ajTrue; /* test the query field(s) */ iterfield = ajListIterNewread(thys->QueryFields); while(!ajListIterDone(iterfield)) { field = ajListIterGet(iterfield); ajDebug(" field: '%S' Query: '%S'\n", field->Field, field->Wildquery); if(ajStrMatchC(field->Field, "id")) { ajDebug(" id test: '%S'\n", resource->Id); if(thys->CaseId) { if(ajStrMatchWildS(resource->Id, field->Wildquery)) { ajListIterDel(&iterfield); return ajTrue; } } else { if(ajStrMatchWildCaseS(resource->Id, field->Wildquery)) { ajListIterDel(&iterfield); return ajTrue; } } ajDebug("id test failed\n"); tested = ajTrue; ok = ajFalse; } if(ajStrMatchC(field->Field, "acc")) /* test id, use trueid */ { if(ajStrMatchWildCaseS(resource->Id, field->Wildquery)) { ajListIterDel(&iterfield); return ajTrue; } } } ajListIterDel(&iterfield); if(!tested) /* nothing to test, so accept it anyway */ { ajDebug(" no tests: assume OK\n"); return ajTrue; } ajDebug("result: %B\n", ok); return ok; } /* @funcstatic resourceDefine ************************************************* ** ** Make sure all data data object attributes are defined ** using values from the data input object if needed ** ** @param [w] thys [AjPResource] Data resource data returned. ** @param [u] resourcein [AjPResourcein] Data resource data input definitions ** @return [AjBool] ajTrue on success. ** @@ ******************************************************************************/ static AjBool resourceDefine(AjPResource thys, AjPResourcein resourcein) { /* if values are missing in the data object, we can use defaults from resourcein or calculate where possible */ /* assign the dbname if defined in the resourcein object */ if(ajStrGetLen(resourcein->Input->Db)) ajStrAssignS(&thys->Db, resourcein->Input->Db); return ajTrue; } /* @funcstatic resourceinReadFmt ********************************************** ** ** Tests whether data data can be read using the specified format. ** Then tests whether the data data matches data data query criteria ** and checks any specified type. Applies upper and lower case. ** ** @param [u] resourcein [AjPResourcein] Data resource data input object ** @param [w] resource [AjPResource] Data resource data object ** @param [r] format [ajuint] input format code ** @return [ajuint] 0 if successful. ** 1 if the query match failed. ** 2 if the data data type failed ** 3 if it failed to read any data data ** @@ ** This is the only function that calls the appropriate Read function ** resourceinReadXxxxxx where Xxxxxxx is the supported data data format. ** ** Some of the resourceReadXxxxxx functions fail to reset the buffer correctly, ** which is a very serious problem when cycling through all of them to ** identify an unknown format. The extra ajFileBuffReset call at the end is ** intended to address this problem. The individual functions should still ** reset the buffer in case they are called from elsewhere. ** ******************************************************************************/ static ajuint resourceinReadFmt(AjPResourcein resourcein, AjPResource resource, ajuint format) { ajDebug("++resourceinReadFmt format %d (%s) '%S'\n", format, resourceinFormatDef[format].Name, resourcein->Input->Qry); resourcein->Input->Records = 0; /* Calling funclist resourceinFormatDef() */ if(resourceinFormatDef[format].Read(resourcein, resource)) { ajDebug("resourceinReadFmt success with format %d (%s)\n", format, resourceinFormatDef[format].Name); ajDebug("id: '%S'\n", resource->Id); resourcein->Input->Format = format; ajStrAssignC(&resourcein->Input->Formatstr, resourceinFormatDef[format].Name); ajStrAssignC(&resource->Formatstr, resourceinFormatDef[format].Name); ajStrAssignEmptyS(&resource->Db, resourcein->Input->Db); ajStrAssignS(&resource->Filename, resourcein->Input->Filename); if(resourceinQueryMatch(resourcein->Input->Query, resource)) { /* ajResourceinTrace(resourcein); */ return FMT_OK; } ajDebug("query match failed, continuing ...\n"); ajResourceClear(resource); return FMT_NOMATCH; } else { ajDebug("Testing input buffer: IsBuff: %B Eof: %B\n", ajFilebuffIsBuffered(resourcein->Input->Filebuff), ajFilebuffIsEof(resourcein->Input->Filebuff)); if (!ajFilebuffIsBuffered(resourcein->Input->Filebuff) && ajFilebuffIsEof(resourcein->Input->Filebuff)) return FMT_EOF; ajFilebuffReset(resourcein->Input->Filebuff); ajDebug("Format %d (%s) failed, " "file buffer reset by resourceinReadFmt\n", format, resourceinFormatDef[format].Name); /* ajFilebuffTraceFull(resourcein->Filebuff, 10, 10);*/ } ajDebug("++resourceinReadFmt failed - nothing read\n"); return FMT_FAIL; } /* @funcstatic resourceinRead ************************************************* ** ** Given data in a resourcein structure, tries to read everything needed ** using the specified format or by trial and error. ** ** @param [u] resourcein [AjPResourcein] Data resource data input object ** @param [w] resource [AjPResource] Data resource data object ** @return [AjBool] ajTrue on success ** @@ ******************************************************************************/ static AjBool resourceinRead(AjPResourcein resourcein, AjPResource resource) { ajuint i; ajuint istat = 0; ajuint jstat = 0; AjPFilebuff buff = resourcein->Input->Filebuff; AjBool ok; AjPTextAccess textaccess = resourcein->Input->Query->TextAccess; AjPResourceAccess resourceaccess = resourcein->Input->Query->Access; ajResourceClear(resource); ajDebug("resourceinRead: cleared\n"); if(resourcein->Input->Single && resourcein->Input->Count) { /* ** One data data item at a time is read. ** The first data data item was read by ACD ** for the following ones we need to reset the AjPResourcein ** ** Single is set by the access method */ ajDebug("resourceinRead: single access - count %d - call access" " routine again\n", resourcein->Input->Count); /* Calling funclist resourceinAccess() */ if(textaccess) { if(!textaccess->Access(resourcein->Input)) { ajDebug("resourceinRead: textaccess->Access(resourcein->Input) " "*failed*\n"); return ajFalse; } } if(resourceaccess) { if(!resourceaccess->Access(resourcein)) { ajDebug("resourceinRead: resourceaccess->Access(resourcein) " "*failed*\n"); return ajFalse; } } buff = resourcein->Input->Filebuff; } ajDebug("resourceinRead: resourcein format %d '%S'\n", resourcein->Input->Format, resourcein->Input->Formatstr); resourcein->Input->Count++; if(!resourcein->Input->Filebuff) return ajFalse; ok = ajFilebuffIsBuffered(resourcein->Input->Filebuff); while(ok) { /* skip blank lines */ ok = ajBuffreadLine(resourcein->Input->Filebuff, &resourceinReadLine); if(!ajStrIsWhite(resourceinReadLine)) { ajFilebuffClear(resourcein->Input->Filebuff,1); break; } } if(!resourcein->Input->Format) { /* no format specified, try all defaults */ for(i = 1; resourceinFormatDef[i].Name; i++) { if(!resourceinFormatDef[i].Try) /* skip if Try is ajFalse */ continue; ajDebug("resourceinRead:try format %d (%s)\n", i, resourceinFormatDef[i].Name); istat = resourceinReadFmt(resourcein, resource, i); switch(istat) { case FMT_OK: ajDebug("++resourceinRead OK, set format %d\n", resourcein->Input->Format); resourceDefine(resource, resourcein); return ajTrue; case FMT_BADTYPE: ajDebug("resourceinRead: (a1) " "resourceinReadFmt stat == BADTYPE *failed*\n"); return ajFalse; case FMT_FAIL: ajDebug("resourceinRead: (b1) " "resourceinReadFmt stat == FAIL *failed*\n"); break; /* we can try next format */ case FMT_NOMATCH: ajDebug("resourceinRead: (c1) " "resourceinReadFmt stat==NOMATCH try again\n"); break; case FMT_EOF: ajDebug("resourceinRead: (d1) " "resourceinReadFmt stat == EOF *failed*\n"); return ajFalse; /* EOF and unbuffered */ case FMT_EMPTY: ajWarn("data data '%S' has zero length, ignored", ajResourceGetQryS(resource)); ajDebug("resourceinRead: (e1) " "resourceinReadFmt stat==EMPTY try again\n"); break; default: ajDebug("unknown code %d from resourceinReadFmt\n", stat); } ajResourceClear(resource); if(resourcein->Input->Format) break; /* we read something */ ajFilebuffTrace(resourcein->Input->Filebuff); } if(!resourcein->Input->Format) { /* all default formats failed, give up */ ajDebug("resourceinRead:all default formats failed, give up\n"); return ajFalse; } ajDebug("++resourceinRead set format %d\n", resourcein->Input->Format); } else { /* one format specified */ ajDebug("resourceinRead: one format specified\n"); ajFilebuffSetUnbuffered(resourcein->Input->Filebuff); ajDebug("++resourceinRead known format %d\n", resourcein->Input->Format); istat = resourceinReadFmt(resourcein, resource, resourcein->Input->Format); switch(istat) { case FMT_OK: resourceDefine(resource, resourcein); return ajTrue; case FMT_BADTYPE: ajDebug("resourceinRead: (a2) " "resourceinReadFmt stat == BADTYPE *failed*\n"); return ajFalse; case FMT_FAIL: ajDebug("resourceinRead: (b2) " "resourceinReadFmt stat == FAIL *failed*\n"); return ajFalse; case FMT_NOMATCH: ajDebug("resourceinRead: (c2) " "resourceinReadFmt stat == NOMATCH *try again*\n"); break; case FMT_EOF: ajDebug("resourceinRead: (d2) " "resourceinReadFmt stat == EOF *try again*\n"); if(resourcein->Input->Records) ajErr("Error reading file '%F' with format '%s': " "end-of-file before end of data " "(read %u records)", ajFilebuffGetFile(resourcein->Input->Filebuff), resourceinFormatDef[resourcein->Input->Format].Name, resourcein->Input->Records); break; /* simply end-of-file */ case FMT_EMPTY: ajWarn("resource data '%S' has zero length, ignored", ajResourceGetQryS(resource)); ajDebug("resourceinRead: (e2) " "resourceinReadFmt stat == EMPTY *try again*\n"); break; default: ajDebug("unknown code %d from resourceinReadFmt\n", stat); } ajResourceClear(resource); /* 1 : read, failed to match id/acc/query */ } /* failed - probably entry/accession query failed. Can we try again? */ ajDebug("resourceinRead failed - try again with format %d '%s' code %d\n", resourcein->Input->Format, resourceinFormatDef[resourcein->Input->Format].Name, istat); ajDebug("Search:%B Chunk:%B Data:%x ajFileBuffEmpty:%B\n", resourcein->Input->Search, resourcein->Input->ChunkEntries, resourcein->Input->TextData, ajFilebuffIsEmpty(buff)); if(ajFilebuffIsEmpty(buff) && resourcein->Input->ChunkEntries) { if(textaccess && !textaccess->Access(resourcein->Input)) return ajFalse; else if(resourceaccess && !resourceaccess->Access(resourcein)) return ajFalse; buff = resourcein->Input->Filebuff; } /* need to check end-of-file to avoid repeats */ while(resourcein->Input->Search && (resourcein->Input->TextData || !ajFilebuffIsEmpty(buff))) { jstat = resourceinReadFmt(resourcein, resource, resourcein->Input->Format); switch(jstat) { case FMT_OK: resourceDefine(resource, resourcein); return ajTrue; case FMT_BADTYPE: ajDebug("resourceinRead: (a3) " "resourceinReadFmt stat == BADTYPE *failed*\n"); return ajFalse; case FMT_FAIL: ajDebug("resourceinRead: (b3) " "resourceinReadFmt stat == FAIL *failed*\n"); return ajFalse; case FMT_NOMATCH: ajDebug("resourceinRead: (c3) " "resourceinReadFmt stat == NOMATCH *try again*\n"); break; case FMT_EOF: ajDebug("resourceinRead: (d3) " "resourceinReadFmt stat == EOF *failed*\n"); return ajFalse; /* we already tried again */ case FMT_EMPTY: if(istat != FMT_EMPTY) ajWarn("assmebly data '%S' has zero length, ignored", ajResourceGetQryS(resource)); ajDebug("resourceinRead: (e3) " "resourceinReadFmt stat == EMPTY *try again*\n"); break; default: ajDebug("unknown code %d from resourceinReadFmt\n", stat); } ajResourceClear(resource); /* 1 : read, failed to match id/acc/query */ } if(resourcein->Input->Format) ajDebug("resourceinRead: *failed* to read data data %S " "using format %s\n", resourcein->Input->Qry, resourceinFormatDef[resourcein->Input->Format].Name); else ajDebug("resourceinRead: *failed* to read data data %S " "using any format\n", resourcein->Input->Qry); return ajFalse; } /* @funcstatic resourceinReadDrcat ******************************************** ** ** Given data in a data structure, tries to read everything needed ** using drcat format. ** ** @param [u] resourcein [AjPResourcein] Resource input object ** @param [w] resource [AjPResource] resource object ** @return [AjBool] ajTrue on success ** @@ ******************************************************************************/ static AjBool resourceinReadDrcat(AjPResourcein resourcein, AjPResource resource) { AjPFilebuff buff; AjPStr name = NULL; AjPStr rest = NULL; ajlong fpos = 0; ajuint linecnt = 0; AjBool ok = ajTrue; AjPStrTok handle = NULL; AjPResquery resqry = NULL; AjPReslink reslink = NULL; AjPResterm resterm = NULL; AjPStr token = NULL; AjIList iter = NULL; ajDebug("resourceinReadDrcat\n"); ajResourceClear(resource); buff = resourcein->Input->Filebuff; /* ajFilebuffTrace(buff); */ ok = ajBuffreadLine(buff, &resourceinReadLine); while (ok && !ajStrPrefixC(resourceinReadLine, "ID ")) { ok = ajBuffreadLine(buff, &resourceinReadLine); } if(!ok) return ajFalse; ajFilebuffClear(buff, 1); ok = ajBuffreadLinePosStore(buff, &resourceinReadLine, &fpos, resourcein->Input->Text, &resource->TextPtr); ajStrExtractFirst(resourceinReadLine, &rest, &name); ajStrTrimWhite(&rest); ajStrAssignS(&resource->Id, rest); if(ok) ok = ajBuffreadLinePosStore(buff, &resourceinReadLine, &fpos, resourcein->Input->Text, &resource->TextPtr); while(ok && ajStrGetLen(resourceinReadLine) > 1) { linecnt++; ajStrExtractFirst(resourceinReadLine, &rest, &name); ajStrTrimWhite(&rest); if(linecnt > 1 && ajStrMatchC(name, "ID")) { break; } else if(ajStrMatchC(name, "IDalt")) { if(!ajStrMatchC(rest, "None")) ajListstrPushAppend(resource->Idalt, ajStrNewS(rest)); } else if(ajStrMatchC(name, "Acc")) { if(!ajStrMatchC(rest, "None")) ajStrAssignS(&resource->Acc, rest); } else if(ajStrMatchC(name, "Name")) { if(!ajStrMatchC(rest, "None")) ajStrAssignS(&resource->Name, rest); } else if(ajStrMatchC(name, "Desc")) { if(!ajStrMatchC(rest, "None")) ajStrAssignS(&resource->Desc, rest); } else if(ajStrMatchC(name, "URL")) { if(!ajStrMatchC(rest, "None")) ajStrAssignS(&resource->Url, rest); } else if(ajStrMatchC(name, "URLlink")) { if(!ajStrMatchC(rest, "None")) ajStrAssignS(&resource->Urllink, rest); } else if(ajStrMatchC(name, "URLrest")) { if(!ajStrMatchC(rest, "None")) ajStrAssignS(&resource->Urlrest, rest); } else if(ajStrMatchC(name, "URLsoap")) { if(!ajStrMatchC(rest, "None")) ajStrAssignS(&resource->Urlsoap, rest); } else if(ajStrMatchC(name, "Cat")) { if(!ajStrMatchC(rest, "None")) { ajStrTokenAssignC(&handle, rest, ";"); while(ajStrTokenNextParse(&handle, &token)) { ajStrRemoveWhiteExcess(&token); ajListstrPushAppend(resource->Cat, ajStrNewS(token)); } } } else if(ajStrMatchC(name, "EDAMtpc")) { if(!ajStrMatchC(rest, "None")) { resterm = ajRestermNew(); ajStrTokenAssignC(&handle, rest, "|"); ajStrTokenNextParse(&handle, &token); ajStrRemoveWhiteExcess(&token); ajStrAssignS(&resterm->Id, token); ajStrTokenRestParse(&handle, &token); ajStrRemoveWhiteExcess(&token); ajStrAssignS(&resterm->Name, token); ajListPushAppend(resource->Edamtpc, resterm); resterm = NULL; } } else if(ajStrMatchC(name, "EDAMdat")) { if(!ajStrMatchC(rest, "None")) { resterm = ajRestermNew(); ajStrTokenAssignC(&handle, rest, "|"); ajStrTokenNextParse(&handle, &token); ajStrRemoveWhiteExcess(&token); ajStrAssignS(&resterm->Id, token); ajStrTokenRestParse(&handle, &token); ajStrRemoveWhiteExcess(&token); ajStrAssignS(&resterm->Name, token); ajListPushAppend(resource->Edamdat, resterm); resterm = NULL; } } else if(ajStrMatchC(name, "EDAMid")) { if(!ajStrMatchC(rest, "None")) { resterm = ajRestermNew(); ajStrTokenAssignC(&handle, rest, "|"); ajStrTokenNextParse(&handle, &token); ajStrRemoveWhiteExcess(&token); ajStrAssignS(&resterm->Id, token); ajStrTokenRestParse(&handle, &token); ajStrRemoveWhiteExcess(&token); ajStrAssignS(&resterm->Name, token); ajListPushAppend(resource->Edamid, resterm); resterm = NULL; } } else if(ajStrMatchC(name, "EDAMfmt")) { if(!ajStrMatchC(rest, "None")) { resterm = ajRestermNew(); ajStrTokenAssignC(&handle, rest, "|"); ajStrTokenNextParse(&handle, &token); ajStrRemoveWhiteExcess(&token); ajStrAssignS(&resterm->Id, token); ajStrTokenRestParse(&handle, &token); ajStrRemoveWhiteExcess(&token); ajStrAssignS(&resterm->Name, token); ajListPushAppend(resource->Edamfmt, resterm); resterm = NULL; } } else if(ajStrMatchC(name, "Xref")) { if(!ajStrMatchC(rest, "None")) { reslink = ajReslinkNew(); ajStrTokenAssignC(&handle, rest, "|"); ajStrTokenNextParse(&handle, &token); ajStrRemoveWhiteExcess(&token); ajStrAssignS(&reslink->Source, token); ajStrTokenRestParse(&handle, &token); ajStrRemoveWhiteExcess(&token); ajStrAssignS(&reslink->Term, token); reslink->Nterms = (ajint) ajStrCalcCountK(token, ';'); ajListPushAppend(resource->Xref, reslink); reslink = NULL; } } else if(ajStrMatchC(name, "Query")) { if(!ajStrMatchC(rest, "None")) { resqry = ajResqueryNew(); ajStrTokenAssignC(&handle, rest, "|"); ajStrTokenNextParse(&handle, &token); ajStrRemoveWhiteExcess(&token); ajStrAssignS(&resqry->Datatype, token); ajStrTokenNextParse(&handle, &token); ajStrRemoveWhiteExcess(&token); ajStrAssignS(&resqry->Format, token); iter = ajListIterNew(resource->Edamfmt); while(!ajListIterDone(iter)) { resterm = ajListIterGet(iter); if(ajStrMatchS(resqry->Format, resterm->Name)) ajStrAssignS(&resqry->FormatTerm, resterm->Id); } ajListIterDel(&iter); ajStrTokenNextParse(&handle, &token); ajStrRemoveWhiteExcess(&token); ajStrAssignS(&resqry->Term, token); resqry->Nterms = (ajint) ajStrCalcCountK(token, ';'); ajStrTokenRestParse(&handle, &token); ajStrRemoveWhiteExcess(&token); ajStrAssignS(&resqry->Url, token); ajListPushAppend(resource->Query, resqry); resqry = NULL; } } else if(ajStrMatchC(name, "Example")) { if(!ajStrMatchC(rest, "None")) ajListstrPushAppend(resource->Example, ajStrNewS(rest)); } else if(ajStrMatchC(name, "Taxon")) { if(!ajStrMatchC(rest, "None")) { resterm = ajRestermNew(); ajStrTokenAssignC(&handle, rest, "|"); ajStrTokenNextParse(&handle, &token); ajStrRemoveWhiteExcess(&token); ajStrAssignS(&resterm->Id, token); ajStrTokenRestParse(&handle, &token); ajStrRemoveWhiteExcess(&token); ajStrAssignS(&resterm->Name, token); ajListPushAppend(resource->Taxon, resterm); resterm = NULL; } } ok = ajBuffreadLinePosStore(buff, &resourceinReadLine, &fpos, resourcein->Input->Text, &resource->TextPtr); } if(ok) ajFilebuffClearStore(buff, 1, resourceinReadLine, resourcein->Input->Text, &resource->TextPtr); else ajFilebuffClear(buff, 0); ajStrDel(&name); ajStrDel(&rest); ajStrDel(&token); ajStrTokenDel(&handle); return ajTrue; } /* @datasection [none] Miscellaneous ****************************************** ** ** Data input internals ** ** @nam2rule Resourcein Data input ** ******************************************************************************/ /* @section Printing ********************************************************** ** ** Printing details of the internals to a file ** ** @fdata [none] ** ** @nam2rule Resourceinprint ** ** @fcategory output ** ******************************************************************************/ /* @section Print ************************************************************* ** ** Printing to a file ** ** @fdata [none] ** ** @nam3rule Book Print as docbook table ** @nam3rule Html Print as html table ** @nam3rule Wiki Print as wiki table ** @nam3rule Text Print as text ** ** @argrule * outf [AjPFile] output file ** @argrule Text full [AjBool] Print all details ** ** @valrule * [void] ** ** @fcategory cast ** ******************************************************************************/ /* @func ajResourceinprintBook ************************************************ ** ** Reports the internal data structures as a Docbook table ** ** @param [u] outf [AjPFile] Output file ** @return [void] ** @@ ******************************************************************************/ void ajResourceinprintBook(AjPFile outf) { ajuint i = 0; ajuint j = 0; AjPStr namestr = NULL; AjPList fmtlist; AjPStr* names; fmtlist = ajListstrNew(); ajFmtPrintF(outf, "The supported data resource formats" "are summarised in the table below. " "The columns are as follows: " "Input format (format name), " "Try (indicates whether the " "format can be detected automatically on input), and " "Description (short description of " "the format).\n\n"); ajFmtPrintF(outf, "\n"); ajFmtPrintF(outf, " \n"); ajFmtPrintF(outf, " \n"); ajFmtPrintF(outf, " \n"); ajFmtPrintF(outf, " \n"); ajFmtPrintF(outf, " \n"); ajFmtPrintF(outf, " \n"); ajFmtPrintF(outf, " \n"); ajFmtPrintF(outf, " \n"); ajFmtPrintF(outf, " \n"); for(i=1; resourceinFormatDef[i].Name; i++) { if(!resourceinFormatDef[i].Alias) { namestr = ajStrNewC(resourceinFormatDef[i].Name); ajListPushAppend(fmtlist, namestr); namestr = NULL; } } ajListSort(fmtlist, ajStrVcmp); ajListstrToarray(fmtlist, &names); for(i=0; names[i]; i++) { for(j=0; resourceinFormatDef[j].Name; j++) { if(ajStrMatchC(names[i],resourceinFormatDef[j].Name)) { ajFmtPrintF(outf, " \n"); ajFmtPrintF(outf, " \n", resourceinFormatDef[j].Name); ajFmtPrintF(outf, " \n", resourceinFormatDef[j].Try); ajFmtPrintF(outf, " \n", resourceinFormatDef[j].Desc); ajFmtPrintF(outf, " \n"); } } } ajFmtPrintF(outf, " \n"); ajFmtPrintF(outf, "
Input data resource formats
Input FormatTryDescription
%s%B%s
\n"); ajStrDel(&namestr); names = NULL; ajListstrFreeData(&fmtlist); return; } /* @func ajResourceinprintHtml ************************************************ ** ** Reports the internal data structures as an HTML table ** ** @param [u] outf [AjPFile] Output file ** @return [void] ** @@ ******************************************************************************/ void ajResourceinprintHtml(AjPFile outf) { ajuint i = 0; ajuint j = 0; AjPStr namestr = NULL; ajFmtPrintF(outf, ""); ajFmtPrintF(outf, "\n"); ajFmtPrintF(outf, "\n"); for(i=1; resourceinFormatDef[i].Name; i++) { ajStrAssignC(&namestr, resourceinFormatDef[i].Name); if(!resourceinFormatDef[i].Alias) { for(j=i+1; resourceinFormatDef[j].Name; j++) { if(resourceinFormatDef[j].Read == resourceinFormatDef[i].Read) { ajFmtPrintAppS(&namestr, " %s", resourceinFormatDef[j].Name); if(!resourceinFormatDef[j].Alias) { ajWarn("Input format '%s' same as '%s' but not alias", resourceinFormatDef[j].Name, resourceinFormatDef[i].Name); } } } ajFmtPrintF(outf, "\n", namestr, resourceinFormatDef[i].Try); ajFmtPrintF(outf, "\n", resourceinFormatDef[i].Desc); } } ajFmtPrintF(outf, "
Input FormatAutoMultiDescription
\n%S\n%B\n%s\n
\n"); ajStrDel(&namestr); return; } /* @func ajResourceinprintText ************************************************ ** ** Reports the internal data structures ** ** @param [u] outf [AjPFile] Output file ** @param [r] full [AjBool] Full report (usually ajFalse) ** @return [void] ** @@ ******************************************************************************/ void ajResourceinprintText(AjPFile outf, AjBool full) { ajuint i = 0; ajFmtPrintF(outf, "\n"); ajFmtPrintF(outf, "# Data resource input formats\n"); ajFmtPrintF(outf, "# Name Format name (or alias)\n"); ajFmtPrintF(outf, "# Alias Alias name\n"); ajFmtPrintF(outf, "# Try Test for unknown input files\n"); ajFmtPrintF(outf, "# Name Alias Try " "Description"); ajFmtPrintF(outf, "\n"); ajFmtPrintF(outf, "InFormat {\n"); for(i=0; resourceinFormatDef[i].Name; i++) if(full || !resourceinFormatDef[i].Alias) ajFmtPrintF(outf, " %-12s %5B %3B \"%s\"\n", resourceinFormatDef[i].Name, resourceinFormatDef[i].Alias, resourceinFormatDef[i].Try, resourceinFormatDef[i].Desc); ajFmtPrintF(outf, "}\n\n"); return; } /* @func ajResourceinprintWiki ************************************************ ** ** Reports the internal data structures as a wiki table ** ** @param [u] outf [AjPFile] Output file ** @return [void] ** @@ ******************************************************************************/ void ajResourceinprintWiki(AjPFile outf) { ajuint i = 0; ajuint j = 0; AjPStr namestr = NULL; ajFmtPrintF(outf, "{| class=\"wikitable sortable\" border=\"2\"\n"); ajFmtPrintF(outf, "|-\n"); ajFmtPrintF(outf, "!Format!!Try!!" "class=\"unsortable\"|Description\n"); for(i=1; resourceinFormatDef[i].Name; i++) { ajStrAssignC(&namestr, resourceinFormatDef[i].Name); if(!resourceinFormatDef[i].Alias) { for(j=i+1; resourceinFormatDef[j].Name; j++) { if(resourceinFormatDef[j].Read == resourceinFormatDef[i].Read) { ajFmtPrintAppS(&namestr, "
%s", resourceinFormatDef[j].Name); if(!resourceinFormatDef[j].Alias) { ajWarn("Input format '%s' same as '%s' but not alias", resourceinFormatDef[j].Name, resourceinFormatDef[i].Name); } } } ajFmtPrintF(outf, "|-\n"); ajFmtPrintF(outf, "|%S||%B||%s\n", namestr, resourceinFormatDef[i].Try, resourceinFormatDef[i].Desc); } } ajFmtPrintF(outf, "|}\n\n"); ajStrDel(&namestr); return; } /* @section Miscellaneous ***************************************************** ** ** Functions to initialise and clean up internals ** ** @fdata [none] ** ** @nam3rule Exit Clean up and exit ** ** @valrule * [void] ** ** @fcategory misc ** ******************************************************************************/ /* @func ajResourceinExit ***************************************************** ** ** Cleans up data input internal memory ** ** @return [void] ** @@ ******************************************************************************/ void ajResourceinExit(void) { ajStrDel(&resourceinReadLine); ajTableDel(&resourceDbMethods); return; } /* @section Internals ********************************************************* ** ** Functions to return internal values ** ** @fdata [none] ** ** @nam3rule Type Internals for data resource datatype ** @nam4rule Get Return a value ** @nam5rule Fields Known query fields for ajResourceinRead ** @nam5rule Qlinks Known query link operators for ajResourceinRead ** ** @valrule * [const char*] Internal value ** ** @fcategory misc ** ******************************************************************************/ /* @func ajResourceinTypeGetFields ******************************************** ** ** Returns the listof known field names for ajResourceinRead ** ** @return [const char*] List of field names ** @@ ******************************************************************************/ const char* ajResourceinTypeGetFields(void) { return "id acc"; } /* @func ajResourceinTypeGetQlinks ******************************************** ** ** Returns the listof known query link operators for ajResourceinRead ** ** @return [const char*] List of field names ** @@ ******************************************************************************/ const char* ajResourceinTypeGetQlinks(void) { return "|"; } /* @datasection [AjPTable] Internal call register table *********************** ** ** Functions to manage the internal call register table that links the ** ajaxdb library functions with code in the core AJAX library. ** ** @nam2rule Resourceaccess Functions to manage resourcedb call tables. ** ******************************************************************************/ /* @section Cast ************************************************************** ** ** Return a reference to the call table ** ** @fdata [AjPTable] resourcedb functions call table ** ** @nam3rule Get Return a value ** @nam4rule Db Database access functions table ** @nam3rule Method Lookup an access method by name ** @nam4rule Test Return true if the access method exists ** @nam4rule MethodGet Return a method value ** @nam5rule Qlinks Return known query links for a named method ** @nam5rule Scope Return scope (entry, query or all) for a named method ** ** @argrule Method method [const AjPStr] Method name ** ** @valrule *Db [AjPTable] Call table of function names and references ** @valrule *Qlinks [const char*] Query link operators ** @valrule *Scope [ajuint] Scope flags ** @valrule *Test [AjBool] True if found ** ** @fcategory cast ** ******************************************************************************/ /* @func ajResourceaccessGetDb ************************************************ ** ** Returns the table in which data database access details are registered ** ** @return [AjPTable] Access functions hash table ** @@ ******************************************************************************/ AjPTable ajResourceaccessGetDb(void) { if(!resourceDbMethods) resourceDbMethods = ajCallTableNew(); return resourceDbMethods; } /* @func ajResourceaccessMethodGetQlinks ************************************** ** ** Tests for a named method for data data reading and returns the ** known query link operators ** ** @param [r] method [const AjPStr] Method required. ** @return [const char*] Known link operators ** @@ ******************************************************************************/ const char* ajResourceaccessMethodGetQlinks(const AjPStr method) { AjPResourceAccess methoddata; methoddata = ajCallTableGetS(resourceDbMethods, method); if(!methoddata) return NULL; return methoddata->Qlink; } /* @func ajResourceaccessMethodGetScope *************************************** ** ** Tests for a named method for data data reading and returns the scope ** (entry, query or all). * ** @param [r] method [const AjPStr] Method required. ** @return [ajuint] Scope flags ** @@ ******************************************************************************/ ajuint ajResourceaccessMethodGetScope(const AjPStr method) { AjPResourceAccess methoddata; ajuint ret = 0; methoddata = ajCallTableGetS(resourceDbMethods, method); if(!methoddata) return 0; if(methoddata->Entry) ret |= AJMETHOD_ENTRY; if(methoddata->Query) ret |= AJMETHOD_QUERY; if(methoddata->All) ret |= AJMETHOD_ALL; return ret; } /* @func ajResourceaccessMethodTest ******************************************* ** ** Tests for a named method for data data reading. ** ** @param [r] method [const AjPStr] Method required. ** @return [AjBool] ajTrue on success. ** @@ ******************************************************************************/ AjBool ajResourceaccessMethodTest(const AjPStr method) { if(ajCallTableGetS(resourceDbMethods, method)) return ajTrue; return ajFalse; } /* @funcstatic resourceinQryRestore ******************************************* ** ** Restores a data input specification from an AjPQueryList node ** ** @param [w] resourcein [AjPResourcein] Data resource input object ** @param [r] node [const AjPQueryList] Query list node ** @return [void] ******************************************************************************/ static void resourceinQryRestore(AjPResourcein resourcein, const AjPQueryList node) { resourcein->Input->Format = node->Format; ajStrAssignS(&resourcein->Input->Formatstr, node->Formatstr); return; } /* @funcstatic resourceinQrySave ********************************************** ** ** Saves a data input specification in an AjPQueryList node ** ** @param [w] node [AjPQueryList] Query list node ** @param [r] resourcein [const AjPResourcein] Data resource input object ** @return [void] ******************************************************************************/ static void resourceinQrySave(AjPQueryList node, const AjPResourcein resourcein) { node->Format = resourcein->Input->Format; ajStrAssignS(&node->Formatstr, resourcein->Input->Formatstr); return; } /* @funcstatic resourceinQryProcess ******************************************* ** ** Converts a data data query into an open file. ** ** Tests for "format::" and sets this if it is found ** ** Then tests for "list:" or "@" and processes as a list file ** using resourceinListProcess which in turn invokes resourceinQryProcess ** until a valid query is found. ** ** Then tests for dbname:query and opens the file (at the correct position ** if the database definition defines it) ** ** If there is no database, looks for file:query and opens the file. ** In this case the file position is not known and data data reading ** will have to scan for the entry/entries we need. ** ** @param [u] resourcein [AjPResourcein] Data resource data input structure. ** @param [u] resource [AjPResource] Data resource data to be read. ** The format will be replaced ** if defined in the query string. ** @return [AjBool] ajTrue on success. ** @@ ******************************************************************************/ static AjBool resourceinQryProcess(AjPResourcein resourcein, AjPResource resource) { AjBool ret = ajTrue; AjPStr qrystr = NULL; AjBool resourcemethod = ajFalse; const AjPStr fmtstr = NULL; AjPTextin textin; AjPQuery qry; AjPResourceAccess resourceaccess = NULL; textin = resourcein->Input; qry = textin->Query; /* pick up the original query string */ qrystr = ajStrNewS(textin->Qry); ajDebug("resourceinQryProcess '%S'\n", qrystr); /* look for a format:: prefix */ fmtstr = ajQuerystrParseFormat(&qrystr, textin, resourceinformatFind); ajDebug("resourceinQryProcess ... fmtstr '%S' '%S'\n", fmtstr, qrystr); /* (seq/feat) DO NOT look for a [range] suffix */ /* look for a list:: or @:: listfile of queries - process and return */ if(ajQuerystrParseListfile(&qrystr)) { ajDebug("resourceinQryProcess ... listfile '%S'\n", qrystr); ret = resourceinListProcess(resourcein, resource, qrystr); ajStrDel(&qrystr); return ret; } /* try general text access methods (file, asis, text database access */ ajDebug("resourceinQryProcess ... no listfile '%S'\n", qrystr); if(!ajQuerystrParseRead(&qrystr, textin, resourceinformatFind, &resourcemethod)) { ajStrDel(&qrystr); return ajFalse; } resourceinFormatSet(resourcein, resource); ajDebug("resourceinQryProcess ... read nontext: %B '%S'\n", resourcemethod, qrystr); ajStrDel(&qrystr); /* we found a non-text method */ if(resourcemethod) { ajDebug("resourceinQryProcess ... call method '%S'\n", qry->Method); ajDebug("resourceinQryProcess ... textin format %d '%S'\n", textin->Format, textin->Formatstr); ajDebug("resourceinQryProcess ... query format '%S'\n", qry->Formatstr); qry->Access = ajCallTableGetS(resourceDbMethods,qry->Method); resourceaccess = qry->Access; return resourceaccess->Access(resourcein); } ajDebug("resourceinQryProcess text method '%S' success\n", qry->Method); return ajTrue; } /* @datasection [AjPList] Query field list ************************************ ** ** Query fields lists are handled internally. Only static functions ** should appear here ** ******************************************************************************/ /* @funcstatic resourceinListProcess ****************************************** ** ** Processes a file of queries. ** This function is called by, and calls, resourceinQryProcess. There is ** a depth check to avoid infinite loops, for example where a list file ** refers to itself. ** ** This function produces a list (AjPList) of queries with all list references ** expanded into lists of queries. ** ** Because queries in a list can have their own format ** the prior settings are stored with each query in the list node so that they ** can be restored after. ** ** @param [u] resourcein [AjPResourcein] Data resource data input ** @param [u] resource [AjPResource] Data resource data ** @param [r] listfile [const AjPStr] Name of list file., ** @return [AjBool] ajTrue on success. ** @@ ******************************************************************************/ static AjBool resourceinListProcess(AjPResourcein resourcein, AjPResource resource, const AjPStr listfile) { AjPList list = NULL; AjPFile file = NULL; AjPStr token = NULL; AjPStrTok handle = NULL; AjBool ret = ajFalse; AjPQueryList node = NULL; static ajint depth = 0; static ajint MAXDEPTH = 16; depth++; ajDebug("++resourceinListProcess %S depth %d\n", listfile, depth); if(depth > MAXDEPTH) ajFatal("Query list too deep"); if(!resourcein->Input->List) resourcein->Input->List = ajListNew(); list = ajListNew(); file = ajFileNewInNameS(listfile); if(!file) { ajErr("Failed to open list file '%S'", listfile); depth--; return ret; } while(ajReadlineTrim(file, &resourceinReadLine)) { resourceinListNoComment(&resourceinReadLine); if(ajStrGetLen(resourceinReadLine)) { ajStrTokenAssignC(&handle, resourceinReadLine, " \t\n\r"); ajStrTokenNextParse(&handle, &token); /* ajDebug("Line '%S'\n");*/ /* ajDebug("token '%S'\n", resourceinReadLine, token); */ if(ajStrGetLen(token)) { ajDebug("++Add to list: '%S'\n", token); AJNEW0(node); ajStrAssignS(&node->Qry, token); resourceinQrySave(node, resourcein); ajListPushAppend(list, node); } ajStrDel(&token); token = NULL; } } ajFileClose(&file); ajStrDel(&token); ajDebug("Trace resourcein->Input->List\n"); ajQuerylistTrace(resourcein->Input->List); ajDebug("Trace new list\n"); ajQuerylistTrace(list); ajListPushlist(resourcein->Input->List, &list); ajDebug("Trace combined resourcein->Input->List\n"); ajQuerylistTrace(resourcein->Input->List); /* ** now try the first item on the list ** this can descend recursively if it is also a list ** which is why we check the depth above */ if(ajListPop(resourcein->Input->List, (void**) &node)) { ajDebug("++pop first item '%S'\n", node->Qry); ajResourceinQryS(resourcein, node->Qry); resourceinQryRestore(resourcein, node); ajStrDel(&node->Qry); ajStrDel(&node->Formatstr); AJFREE(node); ajDebug("descending with query '%S'\n", resourcein->Input->Qry); ret = resourceinQryProcess(resourcein, resource); } ajStrTokenDel(&handle); depth--; ajDebug("++resourceinListProcess depth: %d returns: %B\n", depth, ret); return ret; } /* @funcstatic resourceinListNoComment **************************************** ** ** Strips comments from a character string (a line from an ACD file). ** Comments are blank lines or any text following a "#" character. ** ** @param [u] text [AjPStr*] Line of text from input file. ** @return [void] ** @@ ******************************************************************************/ static void resourceinListNoComment(AjPStr* text) { ajuint i; char *cp; i = ajStrGetLen(*text); if(!i) /* empty string */ return; MAJSTRGETUNIQUESTR(text); cp = strchr(ajStrGetPtr(*text), '#'); if(cp) { /* comment found */ *cp = '\0'; ajStrSetValid(text); } return; } /* @funcstatic resourceinFormatSet ******************************************** ** ** Sets the input format for data data using the data data ** input object's defined format ** ** @param [u] resourcein [AjPResourcein] Data resource data input. ** @param [u] resource [AjPResource] Data resource data ** @return [AjBool] ajTrue on success. ** @@ ******************************************************************************/ static AjBool resourceinFormatSet(AjPResourcein resourcein, AjPResource resource) { if(ajStrGetLen(resourcein->Input->Formatstr)) { ajDebug("... input format value '%S'\n", resourcein->Input->Formatstr); if(resourceinformatFind(resourcein->Input->Formatstr, &resourcein->Input->Format)) { ajStrAssignS(&resource->Formatstr, resourcein->Input->Formatstr); resource->Format = resourcein->Input->Format; ajDebug("...format OK '%S' = %d\n", resourcein->Input->Formatstr, resourcein->Input->Format); } else ajDebug("...format unknown '%S'\n", resourcein->Input->Formatstr); return ajTrue; } else ajDebug("...input format not set\n"); return ajFalse; } /* @datasection [AjPResourceall] Data Resource Input Stream ******************** ** ** Function is for manipulating data resource input stream objects ** ** @nam2rule Resourceall Data resource input stream objects ** ******************************************************************************/ /* @section Data Resource Input Constructors ********************************** ** ** All constructors return a new data resource input stream object by pointer. ** It is the responsibility of the user to first destroy any previous ** data resource input object. The target pointer does not need to be ** initialised to NULL, but it is good programming practice to do so ** anyway. ** ** @fdata [AjPResourceall] ** ** @nam3rule New Constructor ** ** @valrule * [AjPResourceall] Data resource input stream object ** ** @fcategory new ** ******************************************************************************/ /* @func ajResourceallNew ****************************************************** ** ** Creates a new data resource input stream object. ** ** @return [AjPResourceall] New data resource input stream object. ** @@ ******************************************************************************/ AjPResourceall ajResourceallNew(void) { AjPResourceall pthis; AJNEW0(pthis); pthis->Resourcein = ajResourceinNew(); pthis->Resource = ajResourceNew(); return pthis; } /* ==================================================================== */ /* ========================== destructors ============================= */ /* ==================================================================== */ /* @section Data Resource Input Stream Destructors **************************** ** ** Destruction destroys all internal data structures and frees the ** memory allocated for the data resource input stream object. ** ** @fdata [AjPResourceall] ** ** @nam3rule Del Destructor ** ** @argrule Del pthis [AjPResourceall*] Data resource input stream ** ** @valrule * [void] ** ** @fcategory delete ** ******************************************************************************/ /* @func ajResourceallDel ****************************************************** ** ** Deletes a data resource input stream object. ** ** @param [d] pthis [AjPResourceall*] Data resource input stream ** @return [void] ** @@ ******************************************************************************/ void ajResourceallDel(AjPResourceall* pthis) { AjPResourceall thys; if(!pthis) return; thys = *pthis; if(!thys) return; ajResourceinDel(&thys->Resourcein); if(!thys->Returned) ajResourceDel(&thys->Resource); AJFREE(*pthis); return; } /* ==================================================================== */ /* =========================== Modifiers ============================== */ /* ==================================================================== */ /* @section data resource input stream modifiers ******************************* ** ** These functions use the contents of an data resource input stream object and ** update them. ** ** @fdata [AjPResourceall] ** ** @nam3rule Clear Clear all values ** ** @argrule * thys [AjPResourceall] Data resource input stream object ** ** @valrule * [void] ** ** @fcategory modify ** ******************************************************************************/ /* @func ajResourceallClear *************************************************** ** ** Clears a data resource term input stream object back to "as new" condition, ** except for the query list which must be preserved. ** ** @param [w] thys [AjPResourceall] Data resource input stream ** @return [void] ** @@ ******************************************************************************/ void ajResourceallClear(AjPResourceall thys) { ajDebug("ajResourceallClear called\n"); if(!thys) return; ajResourceinClear(thys->Resourcein); ajResourceClear(thys->Resource); thys->Returned = ajFalse; return; } /* @section Data resource input stream casts ********************************** ** ** These functions return the contents of a data resource input stream object ** ** @fdata [AjPResourceall] ** ** @nam3rule Get Get data resource input stream values ** @nam3rule Getresource Get data resource values ** @nam4rule Id Return identifier ** ** @argrule * thys [const AjPResourceall] Data resource input stream object ** ** @valrule * [const AjPStr] String value ** ** @fcategory cast ** ******************************************************************************/ /* @func ajResourceallGetresourceId ******************************************* ** ** Returns the identifier of the current data resource in an input stream ** ** @param [r] thys [const AjPResourceall] Data resource term input stream ** @return [const AjPStr] Identifier ** @@ ******************************************************************************/ const AjPStr ajResourceallGetresourceId(const AjPResourceall thys) { if(!thys) return NULL; ajDebug("ajResourceallGetresourceId called\n"); return ajResourceGetId(thys->Resource); } /* @section resource input **************************************************** ** ** These functions use a data resource input stream object to read data ** ** @fdata [AjPResourceall] ** ** @nam3rule Next Read next data resource ** ** @argrule * thys [AjPResourceall] Data resource input stream object ** @argrule * Presource [AjPResource*] Data resourec object ** ** @valrule * [AjBool] True on success ** ** @fcategory use ** ******************************************************************************/ /* @func ajResourceallNext **************************************************** ** ** Parse a data resource query into format, access, file and entry ** ** Split at delimiters. Check for the first part as a valid format ** Check for the remaining first part as a database name or as a file ** that can be opened. ** Anything left is an entryname spec. ** ** Return the results in the AjPResource object but leave the file open for ** future calls. ** ** @param [w] thys [AjPResourceall] Data resource input stream ** @param [u] Presource [AjPResource*] Data resource returned ** @return [AjBool] ajTrue on success. ** @@ ******************************************************************************/ AjBool ajResourceallNext(AjPResourceall thys, AjPResource *Presource) { if(!thys->Count) { thys->Count = 1; thys->Totresources++; *Presource = thys->Resource; thys->Returned = ajTrue; return ajTrue; } if(ajResourceinRead(thys->Resourcein, thys->Resource)) { thys->Count++; thys->Totresources++; *Presource = thys->Resource; thys->Returned = ajTrue; ajDebug("ajResourceallNext success\n"); return ajTrue; } *Presource = NULL; ajDebug("ajResourceallNext failed\n"); ajResourceallClear(thys); return ajFalse; } /* @datasection [none] Input formats ****************************************** ** ** Input formats internals ** ** @nam2rule Resourceinformat Data data input format specific ** ******************************************************************************/ /* @section cast ************************************************************** ** ** Values for input formats ** ** @fdata [none] ** ** @nam3rule Find Return index to named format ** @nam3rule Term Test format EDAM term ** @nam3rule Test Test format value ** ** @argrule Find format [const AjPStr] Format name ** @argrule Term term [const AjPStr] Format EDAM term ** @argrule Test format [const AjPStr] Format name ** @argrule Find iformat [ajint*] Index matching format name ** ** @valrule * [AjBool] True if found ** ** @fcategory cast ** ******************************************************************************/ /* @funcstatic resourceinformatFind ******************************************* ** ** Looks for the specified format(s) in the internal definitions and ** returns the index. ** ** Sets iformat as the recognised format, and returns ajTrue. ** ** @param [r] format [const AjPStr] Format required. ** @param [w] iformat [ajint*] Index ** @return [AjBool] ajTrue on success. ** @@ ******************************************************************************/ static AjBool resourceinformatFind(const AjPStr format, ajint* iformat) { AjPStr tmpformat = NULL; ajuint i = 0; /* ajDebug("resourceinformatFind '%S'\n", format); */ if(!ajStrGetLen(format)) return ajFalse; ajStrAssignS(&tmpformat, format); ajStrFmtLower(&tmpformat); for(i=0; resourceinFormatDef[i].Name; i++) { /* ajDebug("test %d '%s' \n", i, resourceinFormatDef[i].Name); */ if(ajStrMatchCaseC(tmpformat, resourceinFormatDef[i].Name)) { *iformat = i; ajStrDel(&tmpformat); /* ajDebug("found '%s' at %d\n", resourceinFormatDef[i].Name, i); */ return ajTrue; } } ajErr("Unknown input format '%S'", format); ajStrDel(&tmpformat); return ajFalse; } /* @func ajResourceinformatTerm *********************************************** ** ** Tests whether a data resource data input format term is known ** ** @param [r] term [const AjPStr] Format term EDAM ID ** @return [AjBool] ajTrue if term was accepted ** @@ ******************************************************************************/ AjBool ajResourceinformatTerm(const AjPStr term) { ajuint i; for(i=0; resourceinFormatDef[i].Name; i++) if(ajStrMatchCaseC(term, resourceinFormatDef[i].Name)) return ajTrue; return ajFalse; } /* @func ajResourceinformatTest *********************************************** ** ** Tests whether a named data data input format is known ** ** @param [r] format [const AjPStr] Format term EDAM ID ** @return [AjBool] ajTrue if format was accepted ** @@ ******************************************************************************/ AjBool ajResourceinformatTest(const AjPStr format) { ajuint i; for(i=0; resourceinFormatDef[i].Name; i++) if(ajStrMatchCaseC(format, resourceinFormatDef[i].Name)) return ajTrue; return ajFalse; }