/*
    panicTrap - File-system notifications service for Tcl
    A Tcl interface to the Linux kernel's PanicTrap service.

    Copyright (C) 2008  Alexandros Stergiakis

    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 3 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 General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/*
 * panicTrap.c
 *
 */
#include <stdio.h>


#include <tcl.h>

#include "panicTrap.h"

/*
 * Function Prototypes
 */

static int PanicTrapCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);

/* static void panicTrap_handler(ClientData clientData, int mask); */

/* static void itoa(int n, char *s); */

static void cputs( char * mess);

static void  PanicTrapGetData(Tcl_Interp *interp);

static void PanicTrapCmd_CleanUp(ClientData clientData);

static int doPanic(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);


static TCL_NORETURN1 void PanicProc(const char *format, char *arg1, char *arg2, char *arg3, char  *arg4, char *arg5, char  *arg6, char *arg7,char *arg8);

/*
 * Local storage
 */

static Tcl_Interp *local_interp;
static char *reservedMemory;

/*
 * Function Bodies
 */
#define CPUTS(chan, mess) cputs(mess);

static void cputs(char * mess) {
	/* fprintf(stderr, mess); */
	/* fprintf(stderr, "\n"); */
	/* fflush(stderr);		 */
	puts(mess);
	fflush(stdout);
}

int Panictrap_Init(Tcl_Interp *interp) {
    if (Tcl_InitStubs(interp, "8.5", 0) == NULL) {
        return TCL_ERROR;
    }

    Tcl_CreateObjCommand(interp, "panicTrap", PanicTrapCmd, (ClientData) NULL, PanicTrapCmd_CleanUp);
    Tcl_CreateObjCommand(interp, "Panic", doPanic, (ClientData) NULL, PanicTrapCmd_CleanUp);

    Tcl_SetPanicProc( PanicProc);
    
    /* Grab interpeter pointer and some memory we need after a
       possible out of memory panic */
    
    local_interp = interp;
    reservedMemory = Tcl_Alloc(1028);
    
    Tcl_PkgProvide(interp, "panicTrap", PACKAGE_VERSION);
    return TCL_OK;
}

static void PanicTrapCmd_CleanUp(ClientData clientData) {
	return;
}
#define LEN 30
static void PanicTrapGetData(Tcl_Interp *interp) {
	cputs("try var errorInfo\n");
	cputs((char *) Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY));
	
	int code = TCL_ERROR;
	Tcl_Obj *options = Tcl_GetReturnOptions(interp, code);
	
	cputs("try options\n");
	cputs((char *) Tcl_GetString(options));
	Tcl_DecrRefCount(options);
	cputs("\nNow the 'info frame' for each frame\n");

	int n = 0;
	char str[LEN];
	snprintf(str, LEN ,"info frame %d", n);
	while (Tcl_Eval(interp, str) == TCL_OK) {
		Tcl_Obj *result = Tcl_GetObjResult(interp);
		cputs(Tcl_GetString(result));
		/* Tcl_DecrRefCount(result); */
		n++;
		snprintf(str, LEN ,"info frame %d", n);
		cputs(str);
	}     

 	cputs("ok");
	return;
};

		    
/* The PanicTrapCmd is a test body to see if we are getting the right data.
   When called it will ouput the current tcl stack trace back for the given interp.
*/

static int PanicTrapCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
    PanicTrapGetData(interp);
    return TCL_OK;
};

static TCL_NORETURN1 doPanic(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
	panic("Test the panic code");
}

static TCL_NORETURN void PanicProc(const char *format, char *arg1, char *arg2, char *arg3, char  *arg4, char *arg5, char  *arg6, char *arg7,char *arg8) {

    fprintf(stdout, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
    fprintf(stdout, "\n");
    fprintf(stdout, "Trying to scrape some more info together\n");
    fflush(stdout);

    /* Release our reserved memory */

    Tcl_Free(reservedMemory);
    
    PanicTrapGetData(local_interp);
    cputs("Now we abort");
    TCL_NORETURN1 void abort();
};


