#line 2 "osdep/debuging.dos"
#ifdef DEBUG

#include <sys/timeb.h>

char *
debug_file_name(filename, i)
    char *filename;
    int   i;
{
    char buf[MAXPATH], *p, *pinerc;

    if(!(pinerc = ps_global->pinerc) && !(pinerc = (char *) getenv("PINERC"))){
	char buf2[MAXPATH];

	pinerc = buf;		/* ultimately holds the answer */
	build_path(buf2, ps_global->home_dir, DF_PINEDIR, sizeof(buf2));
	if(is_writable_dir(buf2) == 0){
	    /* $HOME/PINE/ exists!, see if $HOME/PINE/PINERC does too */
	    build_path(buf, buf2, SYSTEM_PINERC, sizeof(buf));
	    if(can_access(buf, ACCESS_EXISTS) != 0){
		/*
		 * no $HOME/PINE/PINERC, make sure
		 * one isn't already in same dir as PINE.EXE
		 */
		build_path(buf2, ps_global->pine_dir, SYSTEM_PINERC,
			   sizeof(buf2));
		if(can_access(buf2, ACCESS_EXISTS) == 0){
		    strncpy(buf, buf2, sizeof(buf)-1);
		    buf[sizeof(buf)-1] = '\0';
		}
		/* else just create $HOME/PINEDIR/PINERC */
	    }
	    /* else just create $HOME/PINEDIR/PINERC */
	}
	else
	  /* no $HOME/pine dir, put PINERC next to PINE.EXE */
	  build_path(buf, ps_global->pine_dir, SYSTEM_PINERC, sizeof(buf));
    }

    if(i !=0)
    	sprintf(filename, "%.*spine%s%s.txt", last_cmpnt(pinerc) - pinerc, 
		pinerc, i == 1 ? "debg" : "DBG", i == 1 ? "" : 
		comatose((long)i));
    else
	sprintf(filename, "%.*s%s", last_cmpnt(pinerc) - pinerc, 
		pinerc, CRASHFILE);
    return(filename);
}


/* 
 * If newval is nonzero, set the debug slot being used to newval. If
 * newval is zero, retrieve the slot number.
 */
int
debug_slot(newval)
    int newval;
{
    static int debug_slot_being_used = 1;

    if(newval)
	debug_slot_being_used = newval;

    return debug_slot_being_used;
}

/*----------------------------------------------------------------------
     Initialize debugging - open the debug log file

  Args: none

 Result: opens the debug logfile for dprints
  ----*/
void
init_debug()
{
    char newfname[MAXPATH+1], filename[MAXPATH+1], nbuf[5];
    int i, j;
    int avail[NUMDEBUGFILES+2];

    /*
     * avail[0]  unused
     *      [1]  pinedebg.txt
     *      [2]  pineDBG2.txt
     *      [3]  pineDBG3.txt
     *      [4]  pineDBG4.txt
     *      [5]  end
     */

    if(!(debug || ps_global->debug_imap || ps_global->debug_tcp))
      return;

    avail[min(NUMDEBUGFILES,9)+1] = -1;
    for(i = min(NUMDEBUGFILES,9); i > 0; i--)
      avail[i] = 1;

    for(i = min(NUMDEBUGFILES,9)-1; i > 0; i--){

	debug_file_name(filename, i);

try_again:
	/*
	 * Look for next available slot after this one so that we
	 * can move filename into it.
	 */
	for(j = i+1; avail[j] != -1; j++){
	    if(avail[j] == 1)
	      break;
	}

	if(avail[j] == 1){			/* there is a slot */
	    /* free up that slot */
	    debug_file_name(newfname, j);
	    if(can_access(newfname, ACCESS_EXISTS) == 0 &&
	       unlink(newfname) != 0){
		/* this means another pine has newfname open */
		avail[j] = 0;
		goto try_again;
	    }
	    /* else, already free */
	}
	/* else no available slots to rename into */

	if(avail[j] == 1){
	    /* try to rename */
	    if(can_access(filename, ACCESS_EXISTS) == 0 &&
	       rename_file(filename, newfname) != 0){
		/* this means that another pine has filename open */
		avail[i] = 0;
	    }
	}
	else{
	    /* just remove since nowhere to put it */
	    if(can_access(filename, ACCESS_EXISTS) == 0 &&
	       unlink(filename) != 0){
		/* this means that another pine has filename open */
		avail[i] = 0;
	    }
	}
    }

    /* locate first available slot to put debugging in */
    for(i = 1; avail[i] != -1; i++){
	if(avail[i] == 1)
	  break;
    }

    if(avail[i] == 1){
	/* and open the debug file */
	debug_file_name(filename, i);
	debugfile = fopen(filename, "w");
	if(debugfile != NULL){
	    time_t now = time((time_t *)0);
	    if(ps_global->debug_flush)
	      setbuf(debugfile, NULL);
	    debug_slot(i);
	    dprint(0, (debugfile, "Debug output of the Pine program (debug=%d debug_imap=%d). Version %s (%s)\n%s\n",
		   debug, ps_global->debug_imap, pine_version, SYSTYPE,
		   ctime(&now)));

	    if(debug > DEFAULT_DEBUG || ps_global->debug_imap > 0 ||
	       ps_global->debug_tcp > 0){
		sprintf(newfname, "Debug file: %s (level=%d imap=%d)", filename,
			debug, ps_global->debug_imap);
		init_error(ps_global, SM_ORDER, 3, 5, newfname);
	    }
	}
    }
}


void
save_debug_on_crash(dfile)
FILE *dfile;
{
    char msg[256], filename[MAXPATH+1], crashname[MAXPATH+1];
    int  status, i;

    time_t now = time((time_t *)0);

    debug_file_name(crashname, 0);
    fprintf(dfile, "save_debug_on_crash: Version %s: debug level %d",
	pine_version, debug);
    fprintf(dfile, "\n                   : %s\n", ctime(&now));
    fprintf(dfile, "Attempting to save debug file to %s\n\n", crashname);

    /* Blat out last n keystrokes */
    fputs("========== Latest Keystrokes =========================\n", dfile);
    while((i = key_playback(0)) != -1)
      fprintf(dfile, "\t%s\t(0x%04.4x)\n", pretty_command(i), i);

    fputs("========== Latest Keystrokes End =====================\n\n", dfile);

#ifdef DEBUGJOURNAL
    fputs("========== Append DebugJournal =======================\n", dfile);
#else /* DEBUGJOURNAL */
    fputs("========== Append Journal =======================\n", dfile);
#endif /* DEBUGJOURNAL */
    debugjournal_to_file(dfile);
#ifdef DEBUGJOURNAL
    fputs("========== Append DebugJournal End ===================\n", dfile);
#else /* DEBUGJOURNAL */
    fputs("========== Append Journal End ===================\n", dfile);
#endif /* DEBUGJOURNAL */

    fclose(dfile);

    status = rename_file (debug_file_name(filename, debug_slot(0)), crashname);

#ifdef _WINDOWS
    sprintf (msg, "Pine debugging information saved in file:  %s",
    	status == 0 ? crashname : filename);
    mswin_messagebox (msg, 0);
#endif
}


#define CHECK_EVERY_N_TIMES 100
#define MAX_DEBUG_FILE_SIZE 200000L
/*
 * This is just to catch runaway Pines that are looping spewing out
 * debugging (and filling up a file system).  The stop doesn't have to be
 * at all precise, just soon enough to hopefully prevent filling the
 * file system.  If the debugging level is high (9 for now), then we're
 * presumably looking for some problem, so don't truncate.
 */
int
do_debug(debug_fp)
FILE *debug_fp;
{
    static int counter = CHECK_EVERY_N_TIMES;
    static int ok = 1;
    long filesize;

    if(debug <= DEFAULT_DEBUG
       && !ps_global->debug_flush
       && !ps_global->debug_tcp
       && !ps_global->debug_timestamp
       && !ps_global->debug_imap
       && ok
       && --counter <= 0){
	if((filesize = fp_file_size(debug_fp)) != -1L)
	  ok = (unsigned long)filesize < (unsigned long)MAX_DEBUG_FILE_SIZE;

	counter = CHECK_EVERY_N_TIMES;
	if(!ok){
	    fprintf(debug_fp, "\n\n --- No more debugging ---\n");
	    fprintf(debug_fp,
		"     (debug file growing too large - over %ld bytes)\n\n",
		MAX_DEBUG_FILE_SIZE);
	    fflush(debug_fp);
	}
    }

    if(ok && ps_global->debug_timestamp)
      fprintf(debug_fp, "\n%s\n", debug_time(0, ps_global->debug_timestamp));

    return(ok);
}


#ifdef DEBUGJOURNAL
#include <stdarg.h>

void
debugjournal(FILE *debug_fp, char *fmt, ...)
{
    va_list args;

    if(debug_fp && debug >= ps_global->dlevel && do_debug(debug_fp)){
	va_start(args, fmt);
	vfprintf(debug_fp, fmt, args);
	va_end(args);
    }

    if(panicking)
      return;

    if(ps_global->dlevel <= 9 || ps_global->dlevel <= debug){
	char    b[64000];

	va_start(args, fmt);
	_vsnprintf(b, sizeof(b), fmt, args);
	va_end(args);

	b[sizeof(b)-1] = '\0';
	add_review_message(b, ps_global->dlevel);
    }
}
#endif /* DEBUGJOURNAL */


/*
 * Returns a pointer to static string for a timestamp.
 *
 * If include_date is set the date is appended.
 */
char *
debug_time(include_date, include_subseconds)
    int include_date;
    int include_subseconds;
{
    time_t          t;
    struct tm      *tm_now;
    static char     timestring[23];
    char            subsecond[8];
    char            datestr[7];
    struct _timeb   timebuffer;

    timestring[0] = '\0';
    t = time((time_t *)0);
    if(include_date){
	tm_now = localtime(&t);
	sprintf(datestr, " %d/%d", tm_now->tm_mon+1, tm_now->tm_mday);
    }
    else
      datestr[0] = '\0';

    if(include_subseconds){
	_ftime(&timebuffer);
	sprintf(subsecond, ".%03ld", timebuffer.millitm);
    }
    else
      subsecond[0] = '\0';

    sprintf(timestring, "%.8s%.7s%.6s", ctime(&t)+11, subsecond, datestr);

    return(timestring);
}
#endif /* DEBUG */


/*
 * This version just returns -1 because this system doesn't have gettimeofday.
 *
 * Returns 0 if ok
 *        -1 if can't do it
 */
int
get_time(our_time_val)
    TIMEVAL_S *our_time_val;
{
    struct _timeb timebuffer;

    _ftime(&timebuffer);
    our_time_val->sec  = (long)timebuffer.time;
    our_time_val->usec = 1000L * (long)timebuffer.millitm;
    return 0;
}


/*
 * Returns the difference between the two values, in microseconds.
 * Value returned is first - second.
 */
long
time_diff(first, second)
    TIMEVAL_S *first,
              *second;
{
    return(1000000L*(first->sec - second->sec) + (first->usec - second->usec));
}


