/*************************************************************************** xsldbgthread.cpp - description ------------------- begin : Thu Dec 20 2001 copyright : (C) 2001 by keith email : keith@linux ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "config.h" #include /* need to create/work with process thread */ #include /* need for EAGAIN */ #include #include #include #include #include #include "../libxsldbg/breakpoint.h" #include "../libxsldbg/xsldbgmsg.h" #include "../libxsldbg/xsldbgthread.h" #include "../libxsldbg/qtnotifier2.h" #ifdef HAVE_READLINE #include #ifdef HAVE_HISTORY #include #endif #endif #define DEBUG_BUFFER_SIZE 500 static char inputBuffer[DEBUG_BUFFER_SIZE]; static char outputBuffer[DEBUG_BUFFER_SIZE]; /*the major structure to hold information about the process thread */ pthread_t mythread; /* The reader for stdout */ pthread_t stdoutReaderThread; FILE *stdoutIO = NULL; /* ----------------------------------------------- private functions ---------------------------------------------------*/ extern "C" { /** * xsldbgGenericErrorFunc: * @ctx: Is Valid * @msg: Is valid * @...: other parameters to use * * Handles print output from xsldbg and passes it to the application */ void xsldbgGenericErrorFunc(void *ctx, const char *msg, ...); xmlChar * qtXslDbgShellReadline(xmlChar * prompt); } /* ----------------------------------------------- end functions ---------------------------------------------------*/ /* setup all application wide items */ int xsldbgThreadInit(void) { int result = 0; fprintf(stderr, "mainInit()\n"); xsltSetGenericErrorFunc(0, xsldbgGenericErrorFunc); setThreadStatus(XSLDBG_MSG_THREAD_INIT); xsldbgSetAppFunc(qtNotifyXsldbgApp); xsldbgSetAppStateFunc(qtNotifyStateXsldbgApp); xsldbgSetTextFunc(qtNotifyTextXsldbgApp); xsldbgSetReadlineFunc(qtXslDbgShellReadline); /* create the thread */ if (pthread_create(&mythread, NULL, xsldbgThreadMain, NULL) != EAGAIN) { int counter; for (counter = 0; counter < 11; counter++){ if (getThreadStatus() != XSLDBG_MSG_THREAD_INIT) break; usleep(250000); /*guess that it will take at most 2.5 seconds to startup */ } /* xsldbg should have started by now if it can */ if (getThreadStatus() == XSLDBG_MSG_THREAD_RUN){ fprintf(stderr, "Created thread\n"); result++; }else fprintf(stderr, "Thread did not start\n"); } else { fprintf(stderr, "Failed to create thread\n"); } return result; } /* tell the thread to stop and free that memory !*/ void xsldbgThreadFree(void) { fprintf(stderr, "xsldbgThreadFree()\n"); if (getThreadStatus() != XSLDBG_MSG_THREAD_DEAD) { int counter; fprintf(stderr, "Killing xsldbg thread\n"); setThreadStatus(XSLDBG_MSG_THREAD_STOP); for (counter = 0; counter < 11; counter++){ if (getThreadStatus() == XSLDBG_MSG_THREAD_DEAD) break; usleep(250000); /*guess that it will take at most 2.5 seconds to stop */ } } } const char *getFakeInput() { return inputBuffer; } /* put text into standard input just like we had typed it */ int fakeInput(const char *text) { int result = 0; if (!text || (getInputReady() == 1) || (getThreadStatus() != XSLDBG_MSG_THREAD_RUN)) return result; // fprintf(stderr, "\nFaking input of \"%s\"\n", text); strncpy(inputBuffer, text, sizeof(inputBuffer)); setInputReady(1); result++; return result; } /* use this function instead of the one that was in debugXSL.c */ /** * qtXslDbgShellReadline: * @prompt: the prompt value * * Read a string * * Returns a copy of the text inputed or NULL if EOF in stdin found. * The caller is expected to free the returned string. */ xmlChar * qtXslDbgShellReadline(xmlChar * prompt) { const char *inputReadBuff; static char last_read[DEBUG_BUFFER_SIZE] = { '\0' }; if (getThreadStatus() != XSLDBG_MSG_THREAD_RUN) { #ifdef HAVE_READLINE xmlChar *line_read; /* Get a line from the user. */ line_read = (xmlChar *) readline((char *) prompt); /* If the line has any text in it, save it on the history. */ if (line_read && *line_read) { add_history((char *) line_read); strncpy((char*)last_read, (char*)line_read, DEBUG_BUFFER_SIZE - 1); } else { /* if only is pressed then try last saved command line */ line_read = (xmlChar *) xmlMemStrdup(last_read); } return (line_read); #else char line_read[DEBUG_BUFFER_SIZE]; if (prompt != NULL) xsltGenericError(xsltGenericErrorContext, "%s", prompt); if (!fgets(line_read, DEBUG_BUFFER_SIZE - 1, stdin)) return (NULL); line_read[DEBUG_BUFFER_SIZE - 1] = 0; /* if only is pressed then try last saved command line */ if ((strlen(line_read) == 0) || (line_read[0] == '\n')) { strcpy(line_read, last_read); } else { strcpy(last_read, line_read); } return (xmlChar *) xmlMemStrdup(line_read); #endif } else{ setInputStatus(XSLDBG_MSG_AWAITING_INPUT); notifyXsldbgApp(XSLDBG_MSG_AWAITING_INPUT, NULL); while (getInputReady() == 0){ usleep(10000); /* have we been told to die */ if (getThreadStatus() == XSLDBG_MSG_THREAD_STOP){ fprintf(stderr, "About to stop thread\n"); xslDebugStatus = DEBUG_QUIT; return NULL; } } setInputStatus(XSLDBG_MSG_READ_INPUT); inputReadBuff = getFakeInput(); if(inputReadBuff){ notifyXsldbgApp(XSLDBG_MSG_READ_INPUT, inputReadBuff); return (xmlChar*)xmlMemStrdup(inputReadBuff); }else{ return NULL; } } } xsldbgErrorMsg msg; xsldbgErrorMsgPtr msgPtr = &msg; xmlChar *msgText = NULL; int qtNotifyStateXsldbgApp(XsldbgMessageEnum type, int commandId, XsldbgCommandStateEnum commandState, const char *text) { int result = 0; msg.type = type; msg.commandId = commandId; msg.commandState = commandState; if (text != NULL) { msg.text = (xmlChar*)xmlMemStrdup(text); if (msg.text == NULL) return result; /* out of memory */ } else msg.text = NULL; notifyXsldbgApp(XSLDBG_MSG_PROCESSING_RESULT, msgPtr); if (msg.text != NULL) { xmlFree(msg.text); msg.text = NULL; } result = 1; return result; } int qtNotifyTextXsldbgApp(XsldbgMessageEnum type, const char *text) { return qtNotifyStateXsldbgApp(type, -1, XSLDBG_COMMAND_NOTUSED, text); } char mainBuffer[DEBUG_BUFFER_SIZE]; static void xsldbgThreadCleanupQt(void); /* this is where the thread get to do all its work */ void * xsldbgThreadMain(void *) { // int defaultArgc = 2; // char *defaultArgv[2]; // int i; if (getThreadStatus() != XSLDBG_MSG_THREAD_INIT){ fprintf(stderr, "xsldbg thread is not ready to be started. Or one is already running.\n"); return NULL; /* we can't start more than one thread of xsldbg */ } // defaultArgv[0] = xmlMemStrdup("xsldbg"); // defaultArgv[1] = xmlMemStrdup("--shell"); /* defaultArgv[2] = xmlMemStrdup("xsldoc.xsl"); defaultArgv[3] = xmlMemStrdup("xsldoc.xml"); */ /* for (i = 0; i < defaultArgc; i++){ if (defaultArgv[i] == NULL){ fprintf(stderr, "Start thread failed. Unable to create xsldbg arguments\n"); return NULL; } } */ xsldbgSetThreadCleanupFunc(xsldbgThreadCleanupQt); setThreadStatus(XSLDBG_MSG_THREAD_RUN); setInputStatus(XSLDBG_MSG_AWAITING_INPUT); fprintf(stderr, "Starting thread\n"); /* call the "main of xsldbg" found in debugXSL.c */ // xsldbgMain(defaultArgc, defaultArgv); xsldbgMain(0,0); fprintf(stderr, "Stopping thread\n"); /* for (i = 0; i < defaultArgc; i++){ xmlFree(defaultArgv[i]); } */ setThreadStatus(XSLDBG_MSG_THREAD_DEAD); setInputStatus(XSLDBG_MSG_PROCESSING_INPUT); notifyXsldbgApp(XSLDBG_MSG_THREAD_DEAD, NULL); return NULL; } /* thread has died so cleanup after it not called directly but via notifyXsldbgApp*/ void xsldbgThreadCleanupQt(void) { fprintf(stderr, "Thread has finished\n"); if (getThreadStatus() == XSLDBG_MSG_THREAD_RUN) { xsldbgThreadFree(); } /* its safe to modify threadStatus as the thread is now dead */ setThreadStatus(XSLDBG_MSG_THREAD_DEAD); } void * xsldbgThreadStdoutReader(void *data) { if (!stdoutIO) return data; while (getThreadStatus() == XSLDBG_MSG_THREAD_RUN){ if (fgets(outputBuffer, sizeof(outputBuffer -1), stdoutIO)){ usleep(10000); strcat(outputBuffer, "\n"); notifyTextXsldbgApp(XSLDBG_MSG_TEXTOUT, outputBuffer); }else{ fprintf(stderr, "Unable to read from stdout from xsldbg\n"); break; } } return data; }