#include /* needed for FILE **/ #include /* needed for free **/ #include #include #include #include #include #include #include // for strcpy #include // for posix threads #include /* for MAXPATHLEN */ #include #include // for stat #include "SDDAS_types.h" #include "libdb.h" /* for dbVirtualName */ #include "pidf.h" #include "pidf_ret.h" #include "pidf_local.h" #include "pidf_parse.h" // definition of pidf_entry #include "symtab.h" // definition of symtab #include "y.tab.h" // for the Y_ defines extern "C" { symtab *GLOBAL_pidf; } typedef std::multimap PIDFMapType; typedef enum {GOOD, BAD, NOT_LOADED} PIDFStatus; typedef struct { std::string fileName; SDDAS_ULONG key; PIDFMapType PIDF; PIDFStatus status; char virtual_name [MAX_IDFS_VIRT_NAME]; time_t timeStamp; } PIDFInfo; std::vector _pidfs; static bool _useFileNameFlag = false; static unsigned int _whichPIDF = 0; static pthread_mutex_t _pidf_mutex = PTHREAD_MUTEX_INITIALIZER; // PRIVATE functions static void AddPIDF (char *filename, SDDAS_ULONG key, char *vinst) { PIDFInfo *pidf = new PIDFInfo; pidf->fileName = filename; pidf->key = key; pidf->status = NOT_LOADED; pidf->timeStamp = 0; memset (pidf->virtual_name, 0, sizeof (pidf->virtual_name)); strncpy (pidf->virtual_name, vinst, sizeof (pidf->virtual_name) - 1); _pidfs.push_back (pidf); } /* Return values are: -1 - ERROR - reread it 0 - file is newer, reread it 1 - everything is fine, do nothing */ /* static int TimeCheck () { struct stat stat_buf; if ((stat (_pidfs [_whichPIDF]->fileName.c_str (), &stat_buf)) == -1) { return -1; // File no longer exists ??? } if (_pidfs [_whichPIDF]->timeStamp == 0) _pidfs [_whichPIDF]->timeStamp = stat_buf.st_mtime; else if (stat_buf.st_mtime > _pidfs [_whichPIDF]->timeStamp) { _pidfs [_whichPIDF]->timeStamp = stat_buf.st_mtime; return 0; } return 1; } */ // returns: false = PIDF needs loading // true = PIDF already loaded // static global _whichPIDF set to the number of the PIDF to use static bool KeyIsLoaded (SDDAS_ULONG key) { bool ret_val; unsigned int i = 0; if (_useFileNameFlag == true) ret_val = (_pidfs [i]->status == GOOD); else { while ((i < _pidfs.size ()) && (key != _pidfs [i]->key)) ++i; if (i == _pidfs.size ()) { _whichPIDF = _pidfs.size (); ret_val = false; } else { _whichPIDF = i; ret_val = true; } } return (ret_val); } static void AddPidfVal (pidf_vals **ret_val, pidf_value_type symtype, const pidf_union *ptr) { pidf_vals *new_node = (pidf_vals *) calloc (1, sizeof (pidf_vals)); pidf_vals *temp; new_node->next = NULL; new_node->type = symtype; switch (symtype) { case P_FLOAT : new_node->val.dval = ptr->dval; break; case P_INT : new_node->val.ival = ptr->ival; break; case P_CHAR : new_node->val.cval = ptr->cval; break; case P_STRING : new_node->val.sval = ptr->sval; break; } // switch if (*ret_val == NULL) *ret_val = new_node; else { temp = *ret_val; while (temp->next != NULL) temp = temp->next; temp->next = new_node; } } static void DeletePidf (int whichPIDF) { // Go through all the PIDFs, freeing strings typedef std::multimap ::const_iterator CIT; CIT cit = _pidfs [whichPIDF]->PIDF.begin (); while (cit != _pidfs [whichPIDF]->PIDF.end ()) { if (cit->second.type == P_STRING) free (cit->second.val.sval); cit++; } _pidfs [whichPIDF]->PIDF.clear (); delete _pidfs [whichPIDF]; _pidfs.erase (_pidfs.begin () + whichPIDF); } static void ClosePIDFs () { for (int i = _pidfs.size () - 1; i >= 0; --i) { DeletePidf (i); } _pidfs.clear (); pthread_mutex_destroy (&_pidf_mutex); } /* Free the storage used by the list pointed to by pointer p */ inline void free_list (symtab *p) { symtab *tmp; while (p != NULL) { if ((p->symtype == Y_STRUCT) || (p->symtype == Y_PIDF)) { free_list ((symtab *) p->ptr); } else { if (p->array_length != 1) for (int i = 0; i < p->array_length; ++i) free (((char **)p->ptr) [i]); free (p->ptr); /* free data storage */ } free (p->symname); p->ptr = NULL; tmp = p->next; free (p); /* free symtab structure */ p = tmp; } } inline int DeleteSYMTAB (symtab *sym) { if (sym != NULL) { free_list (sym); sym = NULL; } return 1; } static void ConvertToMap (int whichPIDF, symtab *p, std::string key) { while (p != NULL) { switch (p->symtype) { case Y_FLOAT : { // fprintf (stdout, "float %s = %12.7e;\n", p->symname, *((float *)p->ptr)); for (int loop = 0; loop < p->array_length; loop++) { pidf_entry entry; entry.type = P_FLOAT; if (p->array_length > 1) entry.val.dval = ((float *)p->ptr) [loop]; else entry.val.dval = *((float *)p->ptr); std::pair value (key+"."+p->symname, entry); _pidfs [whichPIDF]->PIDF.insert (value); } } break; case Y_INT : { // fprintf (stdout, "int %s = %d - %d;\n", p->symname, *((int *)p->ptr), p->array_length); for (int loop = 0; loop < p->array_length; loop++) { pidf_entry entry; entry.type = P_INT; if (p->array_length > 1) entry.val.ival = ((int *)p->ptr) [loop]; else entry.val.ival = *((int *)p->ptr); // std::cout << key+"."+p->symname << " " << p->array_length << "->\"" << entry.val.ival << "\"" << std::endl; std::pair value (key+"."+p->symname, entry); _pidfs [whichPIDF]->PIDF.insert (value); } } break; case Y_STRING : { // fprintf (stdout, "string %s = \"%s\";\n", p->symname, (char *) p->ptr); for (int loop = 0; loop < p->array_length; loop++) { pidf_entry entry; entry.type = P_STRING; if (p->array_length > 1) entry.val.sval = strdup (((char **)p->ptr) [loop]); else entry.val.sval = strdup ((char *)p->ptr); // std::cout << key+"."+p->symname << " " << p->array_length << "->\"" << entry.val.sval << "\"" << std::endl; std::pair value (key+"."+p->symname, entry); _pidfs [whichPIDF]->PIDF.insert (value); } } break; case Y_CHAR : { /* char tempchar = *((char *)p->ptr); if (tempchar > (int) 'Z') fprintf (stdout, "char %s = %d;\n", p->symname, (int) *((char *)p->ptr)); else fprintf (stdout, "char %s = '%c';\n", p->symname, *((char *)p->ptr)); */ for (int loop = 0; loop < p->array_length; loop++) { pidf_entry entry; entry.type = P_CHAR; if (p->array_length > 1) entry.val.cval = ((char *)p->ptr) [loop]; else entry.val.cval = *((char *)p->ptr); std::pair value (key+"."+p->symname, entry); _pidfs [whichPIDF]->PIDF.insert (value); } } break; case Y_STRUCT : { // fprintf (stdout, "struct %s {\n", p->symname); ConvertToMap (whichPIDF, (symtab *) p->ptr, key+"."+p->symname); // fprintf (stdout, "};\n"); } break; case Y_PIDF :{ // fprintf (stdout, "pidf %s {\n", p->symname); ConvertToMap (whichPIDF, (symtab *) p->ptr, p->symname); // fprintf (stdout, "}\n"); } break; default: abort (); }; // switch p = p->next; }; // while } // Return values are -1 and 1 static int ParsePidf (const char *filename) { // Use the LEX/YACC stuff to read a PIDF extern FILE *p_in; if (!(p_in = fopen (filename, "r"))) { char err_str [255]; sprintf (err_str, "ParsePidf: ERROR - opening PIDF %s", filename); perror (err_str); return -1; } while (!(feof (p_in))) { p_parse (); } if (fclose (p_in) != 0) { perror ("ParsePidf: ERROR - closing PIDF"); } // Uncomment on newer versions of Flex // p_lex_destroy (); // Put in a C++ multimap (red/black tree) ConvertToMap (_whichPIDF, GLOBAL_pidf, ""); // Get rid of the old tree structure DeleteSYMTAB (GLOBAL_pidf); // _pidfsInUse [_whichPIDF] = true; // PrintPIDF (_whichPIDF); return 1; } // Load PIDF static int LoadPIDF () { int ret_val; if (_pidfs [_whichPIDF]->status == NOT_LOADED) { if (ParsePidf (_pidfs [_whichPIDF]->fileName.c_str ()) == -1) { ret_val = PIDF_NOT_FOUND; _pidfs [_whichPIDF]->status = BAD; } else { ret_val = _whichPIDF; _pidfs [_whichPIDF]->status = GOOD; } } else ret_val = _whichPIDF; return (ret_val); } #if 0 static void PrintPIDF (int whichPIDF) { typedef std::multimap::const_iterator CIT; CIT cit = _pidfs [whichPIDF]->PIDF.begin (); std::cout << std::endl << "PIDF:" << std::endl; while (cit != _pidfs [whichPIDF]->PIDF.end()) { std::cout << (*cit).first << " - "; switch ((*cit).second.type) { case P_STRING : std::cout << (*cit).second.val.sval; break; case P_FLOAT : std::cout << (*cit).second.val.dval; break; case P_INT : std::cout << (*cit).second.val.ival; break; case P_CHAR : std::cout << (*cit).second.val.cval; break; } // switch std::cout << std::endl; cit++; } } #endif // PUBLIC routines pidf_vals *Find_Name (int whichPIDF, char *tmp, pidf_vals **ret_val) { typedef std::multimap::iterator CIT; typedef std::pair Range; Range range = _pidfs [whichPIDF]->PIDF.equal_range (std::string (tmp)); if (range.first == range.second) { return (NULL); } else { CIT cit = range.first; while (cit != range.second) { AddPidfVal (ret_val, cit->second.type, &cit->second.val); ++cit; } } return (*ret_val); } void FreePidfVals (pidf_vals **ret_val) { pidf_vals *temp, *back; temp = *ret_val; back = NULL; while (temp != NULL) { back = temp->next; free (temp); temp = back; } *ret_val = NULL; } void PIDF_SetFileName (char *filename, char *vinst) { AddPIDF (filename, 0, vinst); _whichPIDF = 0; _useFileNameFlag = true; } const char *PIDF_GetFileName () { return (_pidfs [_whichPIDF]->fileName.c_str ()); } // Must set V to be used in callee int IntroPIDF (SDDAS_ULONG key, char **V) { // Make sure the PIDFs are deleted when the program is quit int ret_val = -1; static bool alreadyCalled = false; if (!alreadyCalled) { alreadyCalled = true; atexit (ClosePIDFs); pthread_mutex_init (&_pidf_mutex, NULL); } // if the _useFileNameFlag is set, we already have a filename. Otherwise // we need to determine the filename from the key pthread_mutex_lock (&_pidf_mutex); if (!KeyIsLoaded (key)) { if (_useFileNameFlag == false) { // Check the database char vinst [MAX_IDFS_VIRT_NAME]; char buf [MAXPATHLEN]; dbVirtualName_r (key, vinst, sizeof (vinst)); int err = FindPidf (key, vinst, buf, sizeof (buf)); AddPIDF (buf, key, vinst); if (err == -1) { ret_val = PIDF_NOT_FOUND; _pidfs [_whichPIDF]->status = BAD; } } ret_val = LoadPIDF (); } else { ret_val = _whichPIDF; // Check times if we already loaded // JM - I disabled this since it was causing lots of core dumps and slowing things down // considerably. Is it really worth it to check the timestamp on EVERY single call // of the ReadPIDF? /* if (_pidfs [_whichPIDF]->status == GOOD) { if (TimeCheck () != 1) { DeletePidf (_whichPIDF); _pidfs [_whichPIDF]->status = NOT_LOADED; ret_val = LoadPIDF (); } } */ } *V = _pidfs [_whichPIDF]->virtual_name; pthread_mutex_unlock (&_pidf_mutex); assert (ret_val != -1); return (ret_val); } int PIDF_InsertIntoPIDF_INT (SDDAS_ULONG key, char *key_name, int value) { char *vinst; std::string real_key; int whichPIDF; if ((whichPIDF = IntroPIDF (key, &vinst)) < 0) return whichPIDF; /* an error occurred */ real_key = "v2_"; real_key += vinst; real_key += "."; real_key += key_name; pidf_entry entry; entry.type = P_INT; entry.val.ival = value; // std::cout << real_key << " " << "->\"" << entry.val.ival << "\"" << std::endl; std::pair pidf_value (real_key, entry); _pidfs [whichPIDF]->PIDF.insert (pidf_value); return (1); } /* int main (int argc, char *argv[]) { if (argc != 2) { printf ("usage: %s \n", argv [0]); } else { ParsePidf (argv [1]); PrintPIDF (0); pidf_vals *p = NULL, *ret_val = NULL; Find_Name (0, "v2_MEXORBMC.bullshit", &ret_val); p = ret_val; while (p != NULL) { std::cout << p->val.ival << std::endl; p = p->next; } } exit (0); } */