/******************************************************************************

    MODUL
	mikro.c

    DESCRIPTION
	hier ist alles, was zu klein war fuer einen vernuenftigen Oberbegriff

    NOTES

    BUGS

    TODO

    EXAMPLES

    SEE ALSO

    AUTHOR
	Bernd "0" Noll (b_noll@informatik.uni-kl.de)

    HISTORY
	******** b_noll created
	01-08-93 b_noll added MICRO_Init
	26-08-93 b_noll added MICRO_Exit
	07-08-94 null updated some docs
	24-09-94 b_noll disabled all toggles execpt for viewmode

*!***************************************************************************
*!
*!  Misc Commands (Mikro.c)
*!
******************************************************************************/

/**************************************
		Includes
**************************************/
#include "defs.h"
/* #include "COM.h" */


/**************************************
	   Implementation
**************************************/


/*
**  some commands to modify the command flow
**
*! >ABORT
*! >UNABORT
*!  they toggle a flag which controlles macro-executing
*!  ABORT sets the break-flag which causes e.g. immediately macro-abortion at keys
*!  or terminates line-execution
*!  UNABORT allows to reset this flag in an AREXX-script,
*!  is the last line produced an error, you may clear the error-flag
*!  if UNABORT is the first (or only) command of a line
*!
*! >BREAK
*! >CONTINUE
*!  these two commands do nearly the same like their C-language conterparts
*!  BREAK leave the current loop-construct and
*!  CONTINUE goes to the next turn of the current loop-construct
*!
**  Note that UNABORT is obsolete since Async Rexxports are introduced,
**	 as after every RexxComm got in mainloop we do a clearbreaks()
*/
/*DEFHELP #cmd program ABORT - abort the current command execution */
DEFUSERCMD("abort", 0, CF_VWM|CF_ICO|CF_COK, void,do_abort, (void),)
{
    SETF_ABORTCOMMAND(Ep, 1);
} /* do_abort */

/*DEFHELP #cmd program UNABORT - clear the ABORT flag (only in an ARexx script) */
DEFUSERCMD("unabort", 0, CF_VWM|CF_ICO|CF_COK, void,do_unabort, (void),)
{
    SETF_ABORTCOMMAND(Ep, 0);
} /* do_unabort */

/*DEFHELP #cmd program BREAK - break out of the current loop (WHILE, REPEAT) */
DEFUSERCMD("break", 0, CF_VWM|CF_ICO|CF_COK, void,do_break, (void),)
{
    SETF_LOOPBREAK( Ep, 1 );
} /* do_break */

/*DEFHELP #cmd program CONTINUE - skip to the end of the current loop (WHILE, REPEAT) */
DEFUSERCMD("continue", 0, CF_VWM|CF_ICO|CF_COK, void,do_continue, (void),)
{
    SETF_LOOPCONT( Ep, 1 );
} /* do_continue */





Prototype void clearbreaks (void);
void clearbreaks (void)
{
    SETF_LOOPCONT( Ep, 0 );
    SETF_LOOPBREAK( Ep, 0 );
    SETF_ABORTCOMMAND(Ep, 0);
} /* clearbreaks */




/*
**  some re-evaluation commands
**
*! >EVAL com
*!
*!  to split longer commandsequences to fit their length down to MAXIA
*!  so MAXIA may stay "small" and anybody can avoid "expression too complex"
*!
*! >FORCE [T|S|F|R|D] command
*!
*!  That's a command that means conjunction
*!  of EVAL, QUIET, UNFAIL and UNTITLE
*!
*!	T == unTitle
*!	S == quiet (no Screen updating)
*!	F == unFail
*!	R == no Requestors
*!	D == enable debugging mode
*!     <no flags> -> simple eval
*!
*!  for this reason we have declared UNTITLE, QUIET and UNFAIL
*!  obsolete, and have removed them;
*!  most of their functionality can be accessed via macros.
*!
*!  >UNFAIL com
*!
*! That's really like EVAL, but it ignore's failures
*! Very useful if U try to call an Command but U don't
*! know if it is one, or if you don't want a failure to break your macro
*!
*!  >UNTITLE com
*!
*!  That's also like EVAL, except for the feature, that
*!  No Title is shown during the macrocall
*!
*!  >QUIET com
*!
*! That's like EVAL, but during execution no window
*! should be refreshed
*! as _No_Screen_Update is increased during operation
*!
*/

/* 25 Sep 1994; the current solution for eval/force is 12 Bytes bigger
		than the previous one, but I do like it much more
		no probs any more to say what is needed ... */

#define DCF_DEBUG      1
#define DCF_NOTITLE    2
#define DCF_NOREDRAW   4
#define DCF_NOFAIL     8
#define DCF_NOREQUEST 16
#define DCF_max       32

static void _do_force (int flags, const char *str) {
    char inter_screen  = GETF_NOSCREENUPDATE(Ep);/* control screen updates */
    char inter_title   = GETF_SHOWTITLE(Ep);     /* control changes in window-titling */
    char inter_request = GETF_NOREQUEST(Ep);     /* Disable flag for requestors */
    char inter_debug   = GETF_DEBUG(Ep);         /* Debugging mode */
    struct TextMarker chk;

    chk.ep     = Ep;
    chk.line   = Ep->line;
    chk.column = Ep->column;

    if (flags & DCF_NOTITLE)
	SETF_SHOWTITLE(Ep, 0);
    if (flags & DCF_NOREQUEST)
	SETF_NOREQUEST(Ep, 1);
    if (flags & DCF_DEBUG)
	SETF_DEBUG(Ep, 1);
    if (flags & DCF_NOREDRAW) {
	SETF_NOSCREENUPDATE( Ep, 1 );
    } /* if */

    buffered_do_command (str);

    if (flags & DCF_NOTITLE)
	SETF_SHOWTITLE(Ep, inter_title);
    if (flags & DCF_NOREQUEST)
	SETF_NOREQUEST(Ep, inter_request);
    if (flags & DCF_DEBUG)
	SETF_DEBUG(Ep, inter_debug);
    if (flags & DCF_NOFAIL) {
	extern char MacroBreak;
	if (MacroBreak != 1)
	    SETF_ABORTCOMMAND(Ep, 0);
//	do_clearallbreaks();        /* simply cancel all breaks after evaluation */
    } /* if */
    if (flags & DCF_NOREDRAW) {
	SETF_NOSCREENUPDATE( Ep, inter_screen );
	if (Ep == chk.ep) {
	    if (Ep->line != chk.line) {
		text_adjust(FALSE);
	    } else if (Ep->column != chk.column) {
		text_adjust(FALSE);
/*	      } else {				*/
/*		  text_redisplay_currline();    */
	    } /* if moved */
/*	  } else {				*/
	} /* if ep */
    } /* if "s" */
} /* _do_force */




/*DEFHELP #cmd program EVAL command - reinvoke the command interpreter; that command can be used to split long commandsequenes to keep MAXIA small */
DEFUSERCMD("eval", 1, CF_VWM|CF_ICO|CF_COK, void,do_eval, (void),)
{
    _do_force(0, av[1]);
} /* do_eval */

/*DEFHELP #cmd program FORCE flags command - set special conditions for executing @{B}command@{UB};
@{B}flags@{UB} can be @{B}F@{UB} ignore errorvalues, @{B}S@{UB} no screenupdates @{B}R@{UB} no errorrequesters, @{B}T@{UB} no title updates, @{B}D@{UB} activate Debug Mode */
DEFUSERCMD("force", 2, CF_VWM|CF_ICO|CF_COK, void,do_force, (void),)
{
    char* typer = av[1];
    int   flags = 0;
    if (typer)                          /* check for any set flags */
	while (*typer)
	    switch ((*(typer++))|32) {
	    case 't':
		flags |= DCF_NOTITLE;
		break;
	    case 's':
		flags |= DCF_NOREDRAW;
		break;
	    case 'f':
		flags |= DCF_NOFAIL;
		break;
	    case 'r':
		flags |= DCF_NOREQUEST;
		break;
	    case 'd':
		flags |= DCF_DEBUG;
		break;
	    default:
DEFMESSAGE( _MIKRO_unknown_flags, "%s:\nInvalid flags '%s'" )
		error (_MIKRO_unknown_flags, av[0], av[1]);
		return;
	    } /* switch */

    _do_force (flags, av[2]);

} /* do_force */

/* the following function have been disabled; */















/*
**  some write - commands
**
*!
*! >PRINTF format parameters
*!
*!  create a string with format and its (up to 8) parameters
*!  and write it into the current text
*!
*! >INSERT text
*! >OVERWRITE text
*!
*!  insert or overwrite text in the current text without respect
*!  to the specialflag INSERTMODE
*!
*/

Prototype void m_write (char *);
void m_write (char *string)
{
    char c;
    char * ptr	= string;
    char * pptr;

/*    char quoted = GETF_AUTOINDENT(Ep); */
/*    SETF_AUTOINDENT(Ep, 0);            */
    while ((c = *ptr)) {
	pptr = ptr;
	while ((c != 0) &&
	    (c != '\t' && c != ('t'&31)) &&
	    (c != '\n' && c != ('n'&31)) &&
	    (c != '\r' && c != ('r'&31))) {
	    ++ptr;
	    c = *(ptr);
	} /* while */
	*ptr = 0;
/* printf ("< '%s'\n", pptr); */
	text_write(pptr);
	if (c != 0) {
	    *ptr = c;
	    ++ptr;
	    switch (c) {
	    case '\t':
	    case 't'&31:
		do_tab();       /* do_command ("tab"); */
		/* !! might be better to create some spaces !! */
		break;
	    case '\n':
	    case 'n'&31:
		do_split();
		do_firstcolumn();
		do_down();      /*  do_command ("split first down"); OR do_command ("return first"); */
		break;
	    case '\r':
	    case 'r'&31:
		av[0] = "b";
		do_bs();        /* do_command ("bs"); */
		break;
	    /* default: */ /* !! oh yea - I know that there are others C-escapes, but these were thought to be important !! */
	    } /* switch */
	} /* if */
    } /* while */
/*    SETF_AUTOINDENT(Ep, quoted); */
} /* m_write */


/*DEFHELP #cmd textedit OVERWRITE text - overwrite text at the current position ignoring $INSERTMODE */
DEFUSERCMD("overwrite", 1, CF_COK, void,do_insertwrite, (void),;)

/*DEFHELP #cmd textedit INSERT text - insert some text at the current position ignoring $INSERTMODE */
DEFUSERCMD("insert", 1, CF_COK, void,do_insertwrite, (void),)
{
    char insertbackup = GETF_INSERTMODE(Ep);

    if (av[0][0] != 'w')
	SETF_INSERTMODE(Ep, (av[0][0] == 'i'));

    m_write(av[1]);

    SETF_INSERTMODE(Ep, insertbackup);
} /* do_insertwrite */


/*DEFHELP #cmd textedit PRINTF format parameters - create a string with printf-style @{B}format@{UB} and its (up to 8) @{B}parameters@{UB} and write it into the current text */
DEFUSERCMD("printf", 2, CF_COK, void,do_printf, (void),)
{
    char* iav = av[0];
    char* arg [10];
    char* aux [10];
    char* ptr = av[2];
    char quoted;
    ULONG arc;
    char* buf;

    if (!(buf = malloc(512))) {
	nomemory();
	abort2();
    } /* if */

    for (arc = 0; arc < 10; ++arc) arg[arc] = NULL;
    arc = 0;
    while ((arg[arc] = breakout (&ptr, &quoted, &aux[arc]))) {
/* printf (">arg %ld == %s\n", arc, arg[arc]); */
	if (++arc >= 10)
	    break;
    } /* while */

    vsprintf (buf, av[1], (va_list)arg);
    m_write (buf);

    while (arc > 0) {
	--arc;
	if (aux[arc])
	    free(aux[arc]);
    } /* while */

    av[0] = iav;
    free (buf);
} /* do_printf */




/*
**  Redefine these names to adjust the used buffers to Your settings
**  the commands are 'atomic' so there should be no interference to
**  other 'atomic' commands using them.
**
**  for XDME changed buffers[0]/buffers[1] to tmp_buffer/tmp_buf2
*/
#define firstbuffer  tmp_buffer




/*
* !  $[SPC.]currentword
* !	 that read-only special-variable
* !	 represents "the word under the cursor"
* !	 that means it finds the beginning of the current word on
* !	 on its own (but we do not move the cursor) if cursor is
* !	 not within a word, it returns the next word of the line
* !	 if there is no next word, an empty string is returned
* !  NOTE this variable is not accessible, if PATCH_VARS is not active
* !
**  current_word		   (uses firstbuffer)
**
**  Returns the word under the cursor,
**  is used by fastscan and should be used by ref and tag instead of
**  their own functions
*/

#define IS_VALID_CHAR(ch)     (isalnum((ch)) || (ch) == '_')

Prototype char *current_word (void);
char *current_word (void) {
    char *str;
    int   i, j = 0;

    str = (char *)firstbuffer;

    i = Ep->column;
    while ((i > 0)      &&  IS_VALID_CHAR(Current[i])) --i; /*  goto beginning of word */
    while ((Current[i]) && !IS_VALID_CHAR(Current[i])) ++i; /* skip spaces and other garbage */

    while (IS_VALID_CHAR(Current[i]) && (j <= LINE_LENGTH)) /* copy "word" into buffer */
	str[j++] = Current[i++];

    str[j] = 0;

    return str;
} /* current_word */

Prototype char *recent_word (void);
char *recent_word (void) {
    char *str;
    int   i, j = 0;

    str = (char *)firstbuffer;
    i = Ep->column;

    while ((i >= 0) && !IS_VALID_CHAR(Current[i])) --i; /* skip spaces and other garbage */
    while ((i >= 0) &&  IS_VALID_CHAR(Current[i])) --i; /* goto beginning of word */

    i ++;
    while (IS_VALID_CHAR(Current[i]) && (j <= LINE_LENGTH)) /* copy "word" into buffer */
	str[j++] = Current[i++];

    str[j] = 0;
    return str;
} /* recent_word */




/*
**  some flags
**  The following commands should be placed into prefs.c
**
*!
*!  Viewmode
*!	That flag disables modifications of the current
*!	text; if TRUE any modifiing command causes an error
*!	(modifiing commands are recognized in do_command with the
*!	flag CF_VWM being FALSE)
*!
*!  ActivateToFront
*!  Windowcycling
*!	These two flags refer to SELECT:
*!
*!	ActivateToFront invokes a "WindowToFront()" every
*!			time, windows are switched
*!	Windowcycling	enables the possibility to switch
*!			to the other end of Textlist, if
*!			one end is reacjed with SELECT next/prev
*!
*!  SourceBreaks
*!	That flag refers to SOURCE
*!	if TRUE if an Abortcommand or a Break occurs
*!	on sourcing level, the operation is aborted
*!	else the next line is executed.
*!
*!  SimpleTabs
*!	That flag is an add to SAVETABS and SAVE[old|as]
*!	if Savetabs is set, SimpleTabs decides to use
*!	TAB-Optimisation until the first non-blank only
*!	(is usable, if a program ignores leading whitespace,
*!	but does not convert tabs to spaces)
*!
*!  FWOvr (Fixed Width Overwrite)
*!	That flag is used in connection with INSERTMODE:
*!	if the User has selected Overwrite, and that flag is
*!	TRUE, DEL will cause replacing the deleted char
*!	by a space instead of shortening the line and
*!	BS is replaced by a simple LEFT (perhaps with writing
*!	a space)
*!
*!  TextLine/LongLine (14-06-93)
*!	this flag is used to disable movement left of the end
*!	of the current line; note: ending spaces are usually
*!	ignored in that mode
*!	(this option was done to satisfy a CED user; dunno if it helps)
*!
*/


DEFUSERCMD("viewmode", 1, CF_VWM|CF_COK|CF_ICO, void,do_viewmode, (void),)
{
    SETF_VIEWMODE(Ep, test_arg(av[1], GETF_VIEWMODE(Ep)));
DEFMESSAGE( _MIKRO_viewmode_txt, "Viewmode %s" )
    title (_MIKRO_viewmode_txt,
	(GETF_VIEWMODE(Ep))? __on: __off);
} /* do_viewmode */




/***************************************
    The following functions are
    disabled ...
    they are not used any more or they
    are replaced w/ macros
***************************************/

/* int is_aborted (void) {
    return (GETF_ABORTCOMMAND(Ep));
} /* is_aborted */

/* Prototype void clearcont (void);
void clearcont (void)  {
    SETF_LOOPCONT( Ep, 0 );
} /* clearcont */

/* Prototype void clearbreak (void);
void clearbreak (void) {
    SETF_LOOPBREAK( Ep, 0 );
} /* clearbreak */


/* DEFHELP #cmd misc UNFAIL command - short for "FORCE F command" */
/* DEFUSERCMD("unfail", 1, CF_VWM|CF_ICO|CF_COK, void, do_unfail, (void),)
{
    _do_force(DCF_NOFAIL, av[1]);
} /* do_unfail */

/* DEFHELP #cmd misc UNTITLE command - short for "FORCE T command" */
/* DEFUSERCMD("untitle", 1, CF_VWM|CF_ICO|CF_COK, void,do_untitle, (void),)
{
    _do_force(DCF_NOTITLE, av[1]);
} /* do_untitle  */

/* DEFHELP #cmd misc QUIET command - short for "FORCE S command" */
/* DEFUSERCMD("quiet", 1, CF_VWM|CF_ICO|CF_COK, void,do_quiet, (void),)
{
    _do_force(DCF_NOREDRAW, av[1]);
} /* do_quiet */

/***************************************
    The following toggle commands are
    disabled in this module; this had
    several reasons:
     * they do belong into "prefs.c".
     * all of them are accessible via
       the variable interface.
     * some of them are not supported
       by "xdme" any more.
***************************************/

/*Prototype  void do_activefront (void);
void do_activefront (void) {
    SETF_ACTIVATETOFRONT(Ep, test_arg (av[1], GETF_ACTIVATETOFRONT(Ep)));
    title ("Activated Windows are %smoved front now",
	    (GETF_ACTIVATETOFRONT(Ep))? "": "NOT ");
} /* do_activefront */

/*Prototype  void do_windowcyc (void);
void do_windowcyc (void) {
    SETF_WINDOWCYCLING(Ep, test_arg (av[1], GETF_WINDOWCYCLING(Ep)));
    title ("Windowcycling is now %s",
	    (GETF_WINDOWCYCLING(Ep))? "ON: "OFF");
} /* do_windowcyc */

/*Prototype  void do_sourcebreak (void);
void do_sourcebreak (void) {
    SETF_SOURCEBREAKS(Ep, test_arg (av[1], GETF_SOURCEBREAKS(Ep)));
    title ("Source - Breaks are %s",
	    (GETF_SOURCEBREAKS(Ep)) "Enabled": "Ignored");
} /* do_sourcebreak */

/*Prototype  void do_simpletabs (void);
void do_simpletabs (void) {
    SETF_SIMPLETABS(Ep, test_arg (av[1], GETF_SIMPLETABS(Ep)));
    title ("Tabsaving %s",
	(!GETF_SAVETABS(Ep))? "OFF":
	    (GETF_SIMPLETABS(Ep))? "up to firstnb": "FULL");
} /* do_simpletabs */

/*Prototype  void do_fwovr (void);
void do_fwovr (void) {
    SETF_FWOVR(Ep, test_arg (av[1], GETF_FWOVR(Ep)));
    title ("Overwrite Delete FixWidth is now %s",
	    (GETF_FWOVR(Ep))? "ON": "OFF");
} /* do_fwovr */

/* Prototype void do_shortline (void);
void do_shortline (void) {
    SETF_SLINE(Ep, test_arg (av[1], GETF_SLINE(Ep)));
    title ("Movement after EoL is now %s",
	    (!GETF_SLINE(Ep))  "ENABLED": "DISABLED");
} /* do_longline */


#ifdef STATIC_COM

    DEFFLAG( 94-10-05, LoopCont,  0 )
    DEFFLAG( 94-10-05, LoopBreak, 0 )
    DEFFLAG( 94-10-05, KillBlock, 0 )

#endif

/******************************************************************************
*****  ENDE mikro.c
******************************************************************************/
