Bonjour, désolé de parler en français, mon niveau d’anglais me limite dans mes échanges.
J’ai édité les sources pour pouvoir faire cette gestion des erreurs dans mon code C #.
Je ne prétends pas savoir si ma solution est correcte ou non, mon niveau en C est comme mon anglais. Mais cela fonctionne pour moi. Voici une approche possible et expérimentale :
J’ai regroupé les fonctions d’écriture dans une structure:
struct MMG5_Console {
FILE* outf;
void (*setlevel) (int level);
void (*printf) (const char* const, ...);
void (*flush) ();
} ;
extern struct MMG5_Console* MMG5_stdconsole_ptr;
int MMG5_Init_console(struct MMG5_Console** console);
static inline void MMG5_console_setlevel(int level) {
if (level == 0) MMG5_stdconsole_ptr->outf = stdout;
else MMG5_stdconsole_ptr->outf = stderr;
}
static inline void MMG5_console_printf(const char* const msg, ...) {
va_list arglist;
va_start(arglist, msg);
vfprintf(MMG5_stdconsole_ptr->outf, msg, arglist);
va_end(arglist);
}
static inline void MMG5_console_flush() {
fflush(MMG5_stdconsole_ptr->outf);
}
Avec quelques macros pour aider
#define INFO (*MMG5_stdconsole_ptr->setlevel) (0); \
(*MMG5_stdconsole_ptr->printf)("\n")
#define WARNING (*MMG5_stdconsole_ptr->setlevel) (1); \
(*MMG5_stdconsole_ptr->printf)("\n ## Warning: %s: ", __func__)
// ERROR define by wingdi.h
#define UERROR (*MMG5_stdconsole_ptr->setlevel) (2); \
(*MMG5_stdconsole_ptr->printf)("\n ## Error: %s: ", __func__)
#define MSG(...) (*MMG5_stdconsole_ptr->printf)(##__VA_ARGS__)
#define FLUSH (*MMG5_stdconsole_ptr->flush)()
La fonction MMG5_Init_console et la structure MMG5_Console me permettent de modifier stderr et stdout à la volée. Ceci est utile lorsque je souhaite que les logs de la première passe soient séparés de ceux de la seconde passe. L’implémentation est vraiment simple
struct MMG5_Console* MMG5_stdconsole_ptr;
// MMG5_Init_console est avant tout une fonction utilitaire
// placer au début des points d'entrée tels que "int main (...)"
int MMG5_Init_console(struct MMG5_Console** console) {
if (*console == NULL) {
*console = (struct MMG5_Console*)calloc(1, sizeof(struct MMG5_Console));
}
if (*console == NULL) {
fprintf(stderr, "\n ## Error: Cannot initialize stdout/stderr ## \n");
return 0;
}
MMG5_stdconsole_ptr = *console;
(*console)->outf = stdout;
(*console)->setlevel = &MMG5_console_setlevel;
(*console)->printf = &MMG5_console_printf;
(*console)->flush = &MMG5_console_flush;
return 1;
}
Pour le reste en effet ce n’est pas trop invasif mais surtout long et répétitif. il s’agit de modifier tous les “printf”
void MMG5_mmgUsage(char *prog) {
INFO;
MSG("\nUsage: %s [-v [n]] [opts..] filein [fileout]\n",prog);
...
ou encore
/** Safe allocation with calloc */
#define MMG5_SAFE_CALLOC(ptr,size,type,law) do \
{ \
ptr = (type*)mycalloc(size,sizeof(type)); \
if ( !ptr ) { \
UERROR; \
MSG("Memory problem: calloc"); \
law; \
} \
}while(0)
Il aurait été possible d’écrire directement WARNING (message)
, mais je les ai décomposés pour pouvoir redéfinir complètement les macros et avoir une logique basée sur un état. INFO
, WARNING
et UERROR
servent donc de commutateur entre les différents flux de sortie.
Sur ma copie locale, je n’ai modifié que les sources de “common” et “mmgs”, dont j’avais besoin.
Si cette implémentation peut vous être utile dites-moi et je vous enverrai un lien vers les sources.
Pour le moment je n’ai pas fini, je me retrouve coincé à un autre niveau. J’essaye d’automatiser la création des liens entre votre code source C et mes sources C#
Passer de
int MMGS_mmgslib(MMG5_pMesh mesh,MMG5_pSol met);
à
[DllImport ("mmg-api.dll")]
internal static extern int MMGS_mmgslib(IntPtr mesh,IntPtr met);
jmv