char *PlugReadMessage(PGLOBAL g, int mid, char *m) { char msgfile[_MAX_PATH], msgid[32], buff[256]; char *msg; FILE *mfile = NULL; //GetPrivateProfileString("Message", msglang, "Message\\english.msg", // msgfile, _MAX_PATH, plgini); //strcat(strcat(strcpy(msgfile, msg_path), msglang()), ".msg"); strcat(strcpy(buff, msglang()), ".msg"); PlugSetPath(msgfile, NULL, buff, msg_path); if (!(mfile = fopen(msgfile, "rt"))) { sprintf(stmsg, "Fail to open message file %s", msgfile); goto err; } // endif mfile for (;;) if (!fgets(buff, 256, mfile)) { sprintf(stmsg, "Cannot get message %d %s", mid, SVP(m)); goto fin; } else if (atoi(buff) == mid) break; if (sscanf(buff, " %*d %s \"%[^\"]", msgid, stmsg) < 2) { // Old message file if (!sscanf(buff, " %*d \"%[^\"]", stmsg)) { sprintf(stmsg, "Bad message file for %d %s", mid, SVP(m)); goto fin; } else m = NULL; } // endif sscanf if (m && strcmp(m, msgid)) { // Message file is out of date strcpy(stmsg, m); goto fin; } // endif m fin: fclose(mfile); err: if (g) { // Called by STEP msg = (char *)PlugSubAlloc(g, NULL, strlen(stmsg) + 1); strcpy(msg, stmsg); } else // Called by MSG or PlgGetErrorMsg msg = stmsg; return msg; } // end of PlugReadMessage
void XTAB::Print(PGLOBAL g, FILE *f, uint n) { char m[64]; memset(m, ' ', n); /* Make margin string */ m[n] = '\0'; for (PTABLE tp = this; tp; tp = tp->Next) { fprintf(f, "%sTABLE: %s.%s %s\n", m, SVP(tp->Schema), tp->Name, SVP(tp->Srcdef)); PlugPutOut(g, f, TYPE_TDB, tp->To_Tdb, n + 2); } /* endfor tp */ } /* end of Print */
void XTAB::Print(PGLOBAL, char *ps, uint z) { char buf[128]; int i, n = (int)z - 1; *ps = '\0'; for (PTABLE tp = this; tp && n > 0; tp = tp->Next) { i = sprintf(buf, "TABLE: %s.%s %s To_Tdb=%p ", SVP(tp->Schema), tp->Name, SVP(tp->Srcdef), tp->To_Tdb); strncat(ps, buf, n); n -= i; } // endif tp } /* end of Print */
LPSTR PlugRemoveType(LPSTR pBuff, LPCSTR FileName) { #if !defined(UNIX) && !defined(UNIV_LINUX) char drive[_MAX_DRIVE]; #else char *drive = NULL; #endif char direc[_MAX_DIR]; char fname[_MAX_FNAME]; char ftype[_MAX_EXT]; _splitpath(FileName, drive, direc, fname, ftype); if (trace > 1) { htrc("after _splitpath: FileName=%s\n", FileName); htrc("drive=%s dir=%s fname=%s ext=%s\n", SVP(drive), direc, fname, ftype); } // endif trace _makepath(pBuff, drive, direc, fname, ""); if (trace > 1) htrc("buff='%s'\n", pBuff); return pBuff; } // end of PlugRemoveType
PCOL TDBASE::ColDB(PGLOBAL g, PSZ name, int num) { int i; PCOLDEF cdp; PCOL cp, colp = NULL, cprec = NULL; if (trace) htrc("ColDB: am=%d colname=%s tabname=%s num=%d\n", GetAmType(), SVP(name), Name, num); for (cdp = To_Def->GetCols(), i = 1; cdp; cdp = cdp->GetNext(), i++) if ((!name && !num) || (name && !stricmp(cdp->GetName(), name)) || num == i) { /*****************************************************************/ /* Check for existence of desired column. */ /* Also find where to insert the new block. */ /*****************************************************************/ for (cp = Columns; cp; cp = cp->GetNext()) if ((num && cp->GetIndex() == i) || (name && !stricmp(cp->GetName(), name))) break; // Found else if (cp->GetIndex() < i) cprec = cp; if (trace) htrc("cdp(%d).Name=%s cp=%p\n", i, cdp->GetName(), cp); /*****************************************************************/ /* Now take care of Column Description Block. */ /*****************************************************************/ if (cp) colp = cp; else if (!(cdp->Flags & U_SPECIAL)) colp = MakeCol(g, cdp, cprec, i); else if (Mode != MODE_INSERT) colp = InsertSpcBlk(g, cdp); if (trace) htrc("colp=%p\n", colp); if (name || num) break; else if (colp && !colp->IsSpecial()) cprec = colp; } // endif Name return (colp); } // end of ColDB
PWMIUT InitWMI(PGLOBAL g, char *nsp, char *classname) { IWbemLocator *loc; char *p; HRESULT res; PWMIUT wp = (PWMIUT)PlugSubAlloc(g, NULL, sizeof(WMIUTIL)); if (trace) htrc("WMIColumns class %s space %s\n", SVP(classname), SVP(nsp)); /*********************************************************************/ /* Set default values for the namespace and class name. */ /*********************************************************************/ if (!nsp) nsp = "root\\cimv2"; if (!classname) { if (!stricmp(nsp, "root\\cimv2")) classname = "ComputerSystemProduct"; else if (!stricmp(nsp, "root\\cli")) classname = "Msft_CliAlias"; else { strcpy(g->Message, "Missing class name"); return NULL; } // endif classname } // endif classname /*********************************************************************/ /* Initialize WMI. */ /*********************************************************************/ //res = CoInitializeEx(NULL, COINIT_MULTITHREADED); res = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); if (FAILED(res)) { sprintf(g->Message, "Failed to initialize COM library. " "Error code = %p", res); return NULL; } // endif res #if 0 // irrelevant for a DLL res = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_CONNECT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL); if (res != RPC_E_TOO_LATE && FAILED(res)) { sprintf(g->Message, "Failed to initialize security. " "Error code = %p", res); CoUninitialize(); return NULL; } // endif Res #endif // 0 res = CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (void**) &loc); if (FAILED(res)) { sprintf(g->Message, "Failed to create Locator. " "Error code = %p", res); CoUninitialize(); return NULL; } // endif res res = loc->ConnectServer(_bstr_t(nsp), NULL, NULL, NULL, 0, NULL, NULL, &wp->Svc); if (FAILED(res)) { sprintf(g->Message, "Could not connect. Error code = %p", res); loc->Release(); CoUninitialize(); return NULL; } // endif res loc->Release(); if (trace) htrc("Successfully connected to namespace.\n"); /*********************************************************************/ /* Perform a full class object retrieval. */ /*********************************************************************/ p = (char*)PlugSubAlloc(g, NULL, strlen(classname) + 7); if (strchr(classname, '_')) strcpy(p, classname); else strcat(strcpy(p, "Win32_"), classname); res = wp->Svc->GetObject(bstr_t(p), 0, 0, &wp->Cobj, 0); if (FAILED(res)) { sprintf(g->Message, "failed GetObject %s in %s\n", classname, nsp); wp->Svc->Release(); wp->Svc = NULL; // MUST be set to NULL (why?) return NULL; } // endif res return wp; } // end of InitWMI
PQRYRES CSVColumns(PGLOBAL g, const char *fn, char sep, char q, int hdr, int mxr, bool info) { static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT, TYPE_INT, TYPE_SHORT}; static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC, FLD_LENGTH, FLD_SCALE}; static unsigned int length[] = {6, 6, 8, 10, 10, 6}; char *p, *colname[MAXCOL], dechar, filename[_MAX_PATH], buf[4096]; int i, imax, hmax, n, nerr, phase, blank, digit, dec, type; int ncol = sizeof(buftyp) / sizeof(int); int num_read = 0, num_max = 10000000; // Statistics int len[MAXCOL], typ[MAXCOL], prc[MAXCOL]; FILE *infile; PQRYRES qrp; PCOLRES crp; if (info) { imax = hmax = 0; length[0] = 128; goto skipit; } // endif info // num_max = atoi(p+1); // Max num of record to test #if defined(WIN32) if (sep == ',' || strnicmp(setlocale(LC_NUMERIC, NULL), "French", 6)) dechar = '.'; else dechar = ','; #else // !WIN32 dechar = '.'; #endif // !WIN32 if (trace) htrc("File %s sep=%c q=%c hdr=%d mxr=%d\n", SVP(fn), sep, q, hdr, mxr); if (!fn) { strcpy(g->Message, MSG(MISSING_FNAME)); return NULL; } // endif fn imax = hmax = nerr = 0; mxr = MY_MAX(0, mxr); for (i = 0; i < MAXCOL; i++) { colname[i] = NULL; len[i] = 0; typ[i] = TYPE_UNKNOWN; prc[i] = 0; } // endfor i /*********************************************************************/ /* Open the input file. */ /*********************************************************************/ PlugSetPath(filename, fn, PlgGetDataPath(g)); if (!(infile= global_fopen(g, MSGID_CANNOT_OPEN, filename, "r"))) return NULL; if (hdr) { /*******************************************************************/ /* Make the column names from the first line. */ /*******************************************************************/ phase = 0; if (fgets(buf, sizeof(buf), infile)) { n = strlen(buf) + 1; buf[n - 2] = '\0'; #if defined(UNIX) // The file can be imported from Windows if (buf[n - 3] == '\r') buf[n - 3] = 0; #endif // UNIX p = (char*)PlugSubAlloc(g, NULL, n); memcpy(p, buf, n); //skip leading blanks for (; *p == ' '; p++) ; if (q && *p == q) { // Header is quoted p++; phase = 1; } // endif q colname[0] = p; } else { sprintf(g->Message, MSG(FILE_IS_EMPTY), fn); goto err; } // endif's for (i = 1; *p; p++) if (phase == 1 && *p == q) { *p = '\0'; phase = 0; } else if (*p == sep && !phase) { *p = '\0'; //skip leading blanks for (; *(p+1) == ' '; p++) ; if (q && *(p+1) == q) { // Header is quoted p++; phase = 1; } // endif q colname[i++] = p + 1; } // endif sep num_read++; imax = hmax = i; for (i = 0; i < hmax; i++) length[0] = MY_MAX(length[0], strlen(colname[i])); } // endif hdr for (num_read++; num_read <= num_max; num_read++) { /*******************************************************************/ /* Now start the reading process. Read one line. */ /*******************************************************************/ if (fgets(buf, sizeof(buf), infile)) { n = strlen(buf); buf[n - 1] = '\0'; #if defined(UNIX) // The file can be imported from Windows if (buf[n - 2] == '\r') buf[n - 2] = 0; #endif // UNIX } else if (feof(infile)) { sprintf(g->Message, MSG(EOF_AFTER_LINE), num_read -1); break; } else { sprintf(g->Message, MSG(ERR_READING_REC), num_read, fn); goto err; } // endif's /*******************************************************************/ /* Make the test for field lengths. */ /*******************************************************************/ i = n = phase = blank = digit = dec = 0; for (p = buf; *p; p++) if (*p == sep) { if (phase != 1) { if (i == MAXCOL - 1) { sprintf(g->Message, MSG(TOO_MANY_FIELDS), num_read, fn); goto err; } // endif i if (n) { len[i] = MY_MAX(len[i], n); type = (digit || (dec && n == 1)) ? TYPE_STRING : (dec) ? TYPE_DOUBLE : TYPE_INT; typ[i] = MY_MIN(type, typ[i]); prc[i] = MY_MAX((typ[i] == TYPE_DOUBLE) ? (dec - 1) : 0, prc[i]); } // endif n i++; n = phase = blank = digit = dec = 0; } else // phase == 1 n++; } else if (*p == ' ') { if (phase < 2) n++; if (blank) digit = 1; } else if (*p == q) { if (phase == 0) { if (blank) if (++nerr > mxr) { sprintf(g->Message, MSG(MISPLACED_QUOTE), num_read); goto err; } else goto skip; n = 0; phase = digit = 1; } else if (phase == 1) { if (*(p+1) == q) { // This is currently not implemented for CSV tables // if (++nerr > mxr) { // sprintf(g->Message, MSG(QUOTE_IN_QUOTE), num_read); // goto err; // } else // goto skip; p++; n++; } else phase = 2; } else if (++nerr > mxr) { // phase == 2 sprintf(g->Message, MSG(MISPLACED_QUOTE), num_read); goto err; } else goto skip; } else { if (phase == 2) if (++nerr > mxr) { sprintf(g->Message, MSG(MISPLACED_QUOTE), num_read); goto err; } else goto skip; // isdigit cannot be used here because of debug assert if (!strchr("0123456789", *p)) { if (!digit && *p == dechar) dec = 1; // Decimal point found else if (blank || !(*p == '-' || *p == '+')) digit = 1; } else if (dec) dec++; // More decimals n++; blank = 1; } // endif's *p if (phase == 1) if (++nerr > mxr) { sprintf(g->Message, MSG(UNBALANCE_QUOTE), num_read); goto err; } else goto skip; if (n) { len[i] = MY_MAX(len[i], n); type = (digit || n == 0 || (dec && n == 1)) ? TYPE_STRING : (dec) ? TYPE_DOUBLE : TYPE_INT; typ[i] = MY_MIN(type, typ[i]); prc[i] = MY_MAX((typ[i] == TYPE_DOUBLE) ? (dec - 1) : 0, prc[i]); } // endif n imax = MY_MAX(imax, i+1); skip: ; // Skip erroneous line } // endfor num_read if (trace) { htrc("imax=%d Lengths:", imax); for (i = 0; i < imax; i++) htrc(" %d", len[i]); htrc("\n"); } // endif trace fclose(infile); skipit: if (trace) htrc("CSVColumns: imax=%d hmax=%d len=%d\n", imax, hmax, length[0]); /*********************************************************************/ /* Allocate the structures used to refer to the result set. */ /*********************************************************************/ qrp = PlgAllocResult(g, ncol, imax, IDS_COLUMNS + 3, buftyp, fldtyp, length, false, false); if (info || !qrp) return qrp; qrp->Nblin = imax; /*********************************************************************/ /* Now get the results into blocks. */ /*********************************************************************/ for (i = 0; i < imax; i++) { if (i >= hmax) { sprintf(buf, "COL%.3d", i+1); p = buf; } else p = colname[i]; if (typ[i] == TYPE_UNKNOWN) // Void column typ[i] = TYPE_STRING; crp = qrp->Colresp; // Column Name crp->Kdata->SetValue(p, i); crp = crp->Next; // Data Type crp->Kdata->SetValue(typ[i], i); crp = crp->Next; // Type Name crp->Kdata->SetValue(GetTypeName(typ[i]), i); crp = crp->Next; // Precision crp->Kdata->SetValue(len[i], i); crp = crp->Next; // Length crp->Kdata->SetValue(len[i], i); crp = crp->Next; // Scale (precision) crp->Kdata->SetValue(prc[i], i); } // endfor i /*********************************************************************/ /* Return the result pointer for use by GetData routines. */ /*********************************************************************/ return qrp; err: fclose(infile); return NULL; } // end of CSVCColumns
PTDBASE TDBPRX::GetSubTable(PGLOBAL g, PTABLE tabp, bool b) { const char *sp = NULL; char *db, *name; bool mysql = true; PTDB tdbp = NULL; TABLE_SHARE *s = NULL; Field* *fp = NULL; PCATLG cat = To_Def->GetCat(); PHC hc = ((MYCAT*)cat)->GetHandler(); LPCSTR cdb, curdb = hc->GetDBName(NULL); THD *thd = (hc->GetTable())->in_use; db = (char*)tabp->GetQualifier(); name = (char*)tabp->GetName(); // Check for eventual loop for (PTABLE tp = To_Table; tp; tp = tp->Next) { cdb = (tp->Qualifier) ? tp->Qualifier : curdb; if (!stricmp(name, tp->Name) && !stricmp(db, cdb)) { sprintf(g->Message, "Table %s.%s pointing on itself", db, name); return NULL; } // endif } // endfor tp if (!tabp->GetSrc()) { if (!(s = GetTableShare(g, thd, db, name, mysql))) return NULL; if (s->is_view && !b) s->field = hc->get_table()->s->field; hc->tshp = s; } else if (b) { // Don't use caller's columns fp = hc->get_table()->field; hc->get_table()->field = NULL; // Make caller use the source definition sp = hc->get_table()->s->option_struct->srcdef; hc->get_table()->s->option_struct->srcdef = tabp->GetSrc(); } // endif srcdef if (mysql) { #if defined(MYSQL_SUPPORT) // Access sub-table via MySQL API if (!(tdbp= cat->GetTable(g, tabp, Mode, "MYPRX"))) { char buf[MAX_STR]; strcpy(buf, g->Message); sprintf(g->Message, "Error accessing %s.%s: %s", db, name, buf); hc->tshp = NULL; goto err; } // endif Define if (db) ((PTDBMY)tdbp)->SetDatabase(tabp->GetQualifier()); if (Mode == MODE_UPDATE || Mode == MODE_DELETE) tdbp->SetName(Name); // For Make_Command #else // !MYSQL_SUPPORT sprintf(g->Message, "%s.%s is not a CONNECT table", db, tblp->Name); goto err; #endif // MYSQL_SUPPORT } else { // Sub-table is a CONNECT table tabp->Next = To_Table; // For loop checking tdbp = cat->GetTable(g, tabp, Mode); } // endif mysql if (s) { if (s->is_view && !b) s->field = NULL; hc->tshp = NULL; } else if (b) { // Restore s structure that can be in cache hc->get_table()->field = fp; hc->get_table()->s->option_struct->srcdef = sp; } // endif s if (trace && tdbp) htrc("Subtable %s in %s\n", name, SVP(((PTDBASE)tdbp)->GetDef()->GetDB())); err: if (s) free_table_share(s); return (PTDBASE)tdbp; } // end of GetSubTable
PQRYRES DBFColumns(PGLOBAL g, char *dp, const char *fn, bool info) { int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT, TYPE_INT, TYPE_SHORT}; XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC, FLD_LENGTH, FLD_SCALE}; unsigned int length[] = {11, 6, 8, 10, 10, 6}; char buf[2], filename[_MAX_PATH]; int ncol = sizeof(buftyp) / sizeof(int); int rc, type, len, field, fields; bool bad; DBFHEADER mainhead; DESCRIPTOR thisfield; FILE *infile = NULL; PQRYRES qrp; PCOLRES crp; if (trace) htrc("DBFColumns: File %s\n", SVP(fn)); if (!info) { if (!fn) { strcpy(g->Message, MSG(MISSING_FNAME)); return NULL; } // endif fn /************************************************************************/ /* Open the input file. */ /************************************************************************/ PlugSetPath(filename, fn, dp); if (!(infile= global_fopen(g, MSGID_CANNOT_OPEN, filename, "rb"))) return NULL; /************************************************************************/ /* Get the first 32 bytes of the header. */ /************************************************************************/ if ((rc = dbfhead(g, infile, filename, &mainhead)) == RC_FX) { fclose(infile); return NULL; } // endif dbfhead /************************************************************************/ /* Allocate the structures used to refer to the result set. */ /************************************************************************/ fields = mainhead.Fields; } else fields = 0; qrp = PlgAllocResult(g, ncol, fields, IDS_COLUMNS + 3, buftyp, fldtyp, length, true, false); if (info || !qrp) { if (infile) fclose(infile); return qrp; } // endif info if (trace) { htrc("Structure of %s\n", filename); htrc("headlen=%hd reclen=%hd degree=%d\n", mainhead.Headlen, mainhead.Reclen, fields); htrc("flags(iem)=%d,%d,%d cp=%d\n", mainhead.Incompleteflag, mainhead.Encryptflag, mainhead.Mdxflag, mainhead.Language); htrc("%hd records, last changed %02d/%02d/%d\n", mainhead.Records, mainhead.Filedate[1], mainhead.Filedate[2], mainhead.Filedate[0] + (mainhead.Filedate[0] <= 30) ? 2000 : 1900); htrc("Field Type Offset Len Dec Set Mdx\n"); } // endif trace buf[1] = '\0'; /**************************************************************************/ /* Do it field by field. We are at byte 32 of file. */ /**************************************************************************/ for (field = 0; field < fields; field++) { bad = FALSE; if (fread(&thisfield, HEADLEN, 1, infile) != 1) { sprintf(g->Message, MSG(ERR_READING_REC), field+1, fn); goto err; } else len = thisfield.Length; if (trace) htrc("%-11s %c %6ld %3d %2d %3d %3d\n", thisfield.Name, thisfield.Type, thisfield.Offset, len, thisfield.Decimals, thisfield.Setfield, thisfield.Mdxfield); /************************************************************************/ /* Now get the results into blocks. */ /************************************************************************/ switch (thisfield.Type) { case 'C': // Characters case 'L': // Logical 'T' or 'F' type = TYPE_STRING; break; case 'N': type = (thisfield.Decimals) ? TYPE_DOUBLE : (len > 10) ? TYPE_BIGINT : TYPE_INT; break; case 'F': type = TYPE_DOUBLE; break; case 'D': type = TYPE_DATE; // Is this correct ??? break; default: if (!info) { sprintf(g->Message, MSG(BAD_DBF_TYPE), thisfield.Type); goto err; } // endif info type = TYPE_ERROR; bad = TRUE; } // endswitch Type crp = qrp->Colresp; // Column Name crp->Kdata->SetValue(thisfield.Name, field); crp = crp->Next; // Data Type crp->Kdata->SetValue((int)type, field); crp = crp->Next; // Type Name if (bad) { buf[0] = thisfield.Type; crp->Kdata->SetValue(buf, field); } else crp->Kdata->SetValue(GetTypeName(type), field); crp = crp->Next; // Precision crp->Kdata->SetValue((int)thisfield.Length, field); crp = crp->Next; // Length crp->Kdata->SetValue((int)thisfield.Length, field); crp = crp->Next; // Scale (precision) crp->Kdata->SetValue((int)thisfield.Decimals, field); } // endfor field qrp->Nblin = field; fclose(infile); #if 0 if (info) { /************************************************************************/ /* Prepare return message for dbfinfo command. */ /************************************************************************/ char buf[64]; sprintf(buf, "Ver=%02x ncol=%hu nlin=%u lrecl=%hu headlen=%hu date=%02d/%02d/%02d", mainhead.Version, fields, mainhead.Records, mainhead.Reclen, mainhead.Headlen, mainhead.Filedate[0], mainhead.Filedate[1], mainhead.Filedate[2]); strcat(g->Message, buf); } // endif info #endif // 0 /**************************************************************************/ /* Return the result pointer for use by GetData routines. */ /**************************************************************************/ return qrp; err: fclose(infile); return NULL; } // end of DBFColumns
PTABDEF OEMDEF::GetXdef(PGLOBAL g) { typedef PTABDEF (__stdcall *XGETDEF) (PGLOBAL, void *); char c, getname[40] = "Get"; PTABDEF xdefp; XGETDEF getdef = NULL; PCATLG cat = Cat; #if defined(WIN32) // Is the DLL already loaded? if (!Hdll && !(Hdll = GetModuleHandle(Module))) // No, load the Dll implementing the function if (!(Hdll = LoadLibrary(Module))) { char buf[256]; DWORD rc = GetLastError(); sprintf(g->Message, MSG(DLL_LOAD_ERROR), rc, Module); FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0, (LPTSTR)buf, sizeof(buf), NULL); strcat(strcat(g->Message, ": "), buf); return NULL; } // endif hDll // The exported name is always in uppercase for (int i = 0; ; i++) { c = Subtype[i]; getname[i + 3] = toupper(c); if (!c) break; } // endfor i // Get the function returning an instance of the external DEF class if (!(getdef = (XGETDEF)GetProcAddress((HINSTANCE)Hdll, getname))) { sprintf(g->Message, MSG(PROCADD_ERROR), GetLastError(), getname); FreeLibrary((HMODULE)Hdll); return NULL; } // endif getdef #else // !WIN32 const char *error = NULL; // Is the library already loaded? // if (!Hdll && !(Hdll = ???)) // Load the desired shared library if (!(Hdll = dlopen(Module, RTLD_LAZY))) { error = dlerror(); sprintf(g->Message, MSG(SHARED_LIB_ERR), Module, SVP(error)); return NULL; } // endif Hdll // The exported name is always in uppercase for (int i = 0; ; i++) { c = Subtype[i]; getname[i + 3] = toupper(c); if (!c) break; } // endfor i // Get the function returning an instance of the external DEF class if (!(getdef = (XGETDEF)dlsym(Hdll, getname))) { error = dlerror(); sprintf(g->Message, MSG(GET_FUNC_ERR), getname, SVP(error)); dlclose(Hdll); return NULL; } // endif getdef #endif // !WIN32 // Just in case the external Get function does not set error messages sprintf(g->Message, MSG(DEF_ALLOC_ERROR), Subtype); // Get the table definition block if (!(xdefp = getdef(g, NULL))) return NULL; // Have the external class do its complete definition if (!cat->Cbuf) { // Suballocate a temporary buffer for the entire column section cat->Cblen = cat->GetSizeCatInfo("Colsize", "8K"); cat->Cbuf = (char*)PlugSubAlloc(g, NULL, cat->Cblen); } // endif Cbuf // Here "OEM" should be replace by a more useful value if (xdefp->Define(g, cat, Name, "OEM")) return NULL; // Ok, return external block return xdefp; } // end of GetXdef