static char rcsid[] = "$Id: mmfcn2.c,v 1.1 1992/09/05 01:13:32 mike Exp $";

/* $Log: mmfcn2.c,v $
 * Revision 1.1  1992/09/05  01:13:32  mike
 * Initial revision
 *
 */

/*
 * mmfcn2.c : Functions that don't fit in mmfcn.c
 */

/* Copyright 1990, 1991, 1992 Craig Durland
 *   Distributed under the terms of the GNU General Public License.
 *   Distributed "as is", without warranties of any kind, but comments,
 *     suggestions and bug reports are welcome.
 */

#include "me2.h"
#include "mm.h"

extern Bag *id_to_bag();
extern Buffer *alloc_buffer(), *Mid_to_buffer(), *nthbuffer();
extern MMDatum RV, TV;			/* in mm.c */

    /* (filter
     *   filter-name
     *   [in-bag-id  (-1 if no bag)]
     *   [out_bag-id (-1 if no bag)]
     *   [insert-output-at-dot]
     * )
     * Result:
     *   RV : boolean
     *     TRUE if everything worked OK
     */
void Mfilter()
{
  Bag *bag_in = NULL, *bag_out = NULL;
  char *filter_name;
  int insert_output_at_dot = FALSE;

	/* get the filter name */
  get1arg(STRING,"OS-filter"); filter_name = RV.val.str;

		/* get in-bag-id if not -1 */
  if (maybearg(1,NUMBER,"OS-filter"))
    if (TV.val.num != -1 && !(bag_in = id_to_bag((int)TV.val.num)))
	arg_bitch("OS-filter");

		/* get out-bag-id if not -1 */
  if (maybearg(2,NUMBER,"OS-filter"))
    if (TV.val.num != -1 && !(bag_out = id_to_bag((int)TV.val.num)))
	arg_bitch("OS-filter");

	/* get [insert-output-at-dot] */
  if (maybearg(3,BOOLEAN,"OS-filter")) insert_output_at_dot = (int)TV.val.num;

  RV.type = BOOLEAN;
  RV.val.num = os_filter(filter_name, bag_in,bag_out, insert_output_at_dot);
}

/* ******************************************************************** */
/* ******************** Buffers *************************************** */
/* ******************************************************************** */

			    /* (buffer-stats buffer-id (array INT stats 6)) */
void Mbuffer_stats()
{
  int x;
  int32 tl1, tl2, tl3, tl4, tl5;

  get2args(NUMBER,BLOB,"buffer-stats");
  buffer_stats(Mid_to_buffer((int)RV.val.num),&tl1,&tl2,&tl3,&x,&tl4,&tl5);
  put_int32(TV.val.blob,    (int32)tl1);	/* buffer size */
  put_int32(TV.val.blob +4, (int32)tl2);	/* dot postition */
  put_int32(TV.val.blob +8, (int32)tl3);	/* lines */
  put_int32(TV.val.blob +12,(int32)tl4);	/* buffer row */
  put_int32(TV.val.blob +16,(int32)tl5);	/* wasted */
  put_int32(TV.val.blob +20,(int32)x);		/* char at dot */
  RV.type = VOID;
}

void Mcreate_buffer()			    /* (create-buffer name [flags]) */
{
  Buffer *bp;
  int32 flags;

  get1arg(STRING,"create-buffer");
  flags = 0;
  if (maybearg(1,NUMBER,"create-buffer")) flags = TV.val.num;
  if (!(bp = alloc_buffer(RV.val.str, flags)))
	MMbitch("create-buffer:  No memory");
/*  set_buffer_flags(bp,flags);*/

  RV.type = NUMBER;
  RV.val.num = bp->id;
}

    /* (nth-buffer [n [id [flags]]])
     * Return the id of the nth buffer starting at <you pick>.
     * If no args, return the count of the current buffer.
     * Input:
     *   n : count.  Default is 0 ie return the id of the current buffer.
     *   id : buffer to start the count at.  Default is current buffer.
     *   flags : skip buffers with any of these flags set.
     * Returns:
     *   Buffer id
     */
void Mnth_buffer()		       /* (nth-buffer n [id [flags]]) => id */
{
#if 0
  Buffer *bp;
  int32 flags;      ?????????????
  int n, id;

  if (!maybearg(0,NUMBER,"nth-buffer"))		/* no args */
  {
    RV.val.num = cntbufs(curbp);
    RV.type = NUMBER;
    return;
  }
  bp = first_buffer;
  n = TV.val.num;
  flags = 0;
  if (maybearg(1,NUMBER,"nth-buffer")) bp = Mid_to_buffer((int)TV.val.num);
  if (maybearg(2,NUMBER,"nth-buffer")) flags = TV.val.num;
  RV.val.num = nthbuffer(bp,n,flags)->id;

#else 
  if (!maybearg(0,NUMBER,"nth-buffer"))			/* no args */
	RV.val.num = cntbufs(curbp);
  else RV.val.num = nthbuffer(first_buffer,(int)TV.val.num,0)->id;

  RV.type = NUMBER;
#endif
}

/* ******************************************************************** */
/* ******************** Marks ***************************************** */
/* ******************************************************************** */

	/* munges: TV */
void get_marks(name, n, mark1,mark2)
  char *name;
  int n;
  Mark **mark1, **mark2;
{
  int mark1_id, mark2_id;

  mark1_id = THE_DOT; mark2_id = THE_MARK;
  if (maybearg(n,  NUMBER,name)) mark1_id = TV.val.num;
  if (maybearg(n+1,NUMBER,name)) mark2_id = TV.val.num;
  if (!(*mark1 = id_to_mark(mark1_id)) || !(*mark2 = id_to_mark(mark2_id)))
	arg_bitch(name);
}

    /* (swap-marks [mark-id mark-id])
     * munges: TV
     */
void Mswap_marks()
{
  int mark1_id, mark2_id;

  mark1_id = THE_DOT; mark2_id = THE_MARK;
  if (maybearg(0,NUMBER,"swap-marks")) mark1_id = TV.val.num;
  if (maybearg(1,NUMBER,"swap-marks")) mark2_id = TV.val.num;

  if (!swap_marks(mark1_id, mark2_id)) MMbitch("swap-marks:  Bad mark(s)!");
}

void Mcompare_marks()		       /* (compare-marks [mark-id mark-id]) */
{
  Mark *mark1, *mark2;
  Region region;

  get_marks("compare-marks",0, &mark1,&mark2);

  if ((RV.val.num = get_region(mark1,mark2,&region)) == 0) MMabort_pgm(0);
  RV.type = NUMBER;
}

    /* (region-stats blob [mark1 [mark2 [goto-top-mark]]]
     * Calculate the stats for a region.  If marks not passed in, use dot
     *   and mark.
     * Input:
     *   blob:  pointer to structure of
     *		(byte type)(int left-edge width height)(INT size)
     *		that hold the region data.
     *	 mark1: one end of the region.  Defaults to dot.
     *	 mark2: the other end of the region.  Defaults to mark.
     *	 goto-top-mark:  If TRUE, move the dot to the upper left
     *     corner of the region.
     *	   Note that I can't swap the marks because one of them might
     *	   not be the dot.
     * Output:
     *   Region data stuffed into blob.
     */
void Mregion_stats()
{
  int x, goto_top;
  Mark *mark1, *mark2;
  Region region;

  get1arg(BLOB,"region-stats");
  get_marks("region-stats",1, &mark1,&mark2);

  goto_top = FALSE;
  if (maybearg(3, BOOLEAN, "region-stats")) goto_top = TV.val.num;

  if ((x = get_rectangle(mark1,mark2,&region)) == 0) MMabort_pgm(0);
  PUT_UINT8(RV.val.blob,  (uint8)x);
  put_int16(RV.val.blob+1, region.ulcol+1);
  put_int16(RV.val.blob+3, region.width);
  put_int16(RV.val.blob+5, region.height);
  put_int32(RV.val.blob+7, region.r_size);

  if (goto_top) jmp_mark(&region.mark);

  RV.type = VOID;
}

/* ******************************************************************** */
/* ******************** Bags ****************************************** */
/* ******************************************************************** */

    /*
     * Append stuff to a bag.
     *   (append-to-bag bag-id TEXT	  <text>)
     *   (append-to-bag bag-id REGION	  [mark1 mark2])
     *   (append-to-bag bag-id CHARACTERS <number>)
     *   (append-to-bag bag-id RECTANGLE  [mark1 mark2])
     */
void Mappend_to_bag()
{
  Bag *bag;
  int s;
  Mark *mark1, *mark2;
  Region region;

  get2args(NUMBER,NUMBER,"append-to-bag");	/* bag-id op */
  if (!(bag = id_to_bag((int)RV.val.num)))
	MMbitch("append-to-bag: bad bag-id");

  switch(TV.val.num)
  {
    case 0:			      /* (append-to-bag bag-id TEXT <text>) */
      get_nth_arg(2,STRING,"append-to-bag");
      s = bag_append(bag, RV.val.str, strlen(RV.val.str));
      break;
    case 1:		      /* (append-to-bag bag-id CHARACTERS <number>) */
      get_nth_arg(2,NUMBER,"append-to-bag");
      s = copy_region_to_bag(the_dot, RV.val.num, bag);
      break;
    case 2:		     /* (append-to-bag bag-id REGION [mark1 mark2]) */
      get_marks("append-to-bag REGION", 2, &mark1,&mark2);
      if (get_region(mark1,mark2, &region) == 0) MMabort_pgm(0);
      s = copy_region_to_bag(&region.mark, region.r_size, bag);
      break;
    case 3:		  /* (append-to-bag bag-id RECTANGLE [mark1 mark2]) */
      get_marks("append-to-bag RECTANGLE", 2, &mark1,&mark2);
      if (!copy_rect(bag, mark1,mark2)) MMabort_pgm(0);
      s = TRUE;
      break;
  }

  if (!s) MMbitch("append-to-bag: Out of memory!");

  RV.type = VOID;
}

    /* Convert a bag to a string.
     * Gonna look a little funny if you convert a rectangle to a string.
     */
void Mbag_to_string()
{
  extern char *bag_to_string();		/* in bag.c */

  Bag *bag;

  get1arg(NUMBER,"bag-to-string");	/* bag-id */
  if (!(bag = id_to_bag((int)RV.val.num)))
	MMbitch("bag-to-string: bad bag-id");

  RV.type = STRING;
  if (!(RV.val.str = bag_to_string(bag)))
	MMbitch("bag-to-string: Out of memory!");
}

/* ******************************************************************** */
/* ******************** System Variables ****************************** */
/* ******************************************************************** */

static int sysvar();

void Msys_var(t,n)
{
  int x;

  x = maybearg(n,NUMBER,"sysvar");
  RV.type = NUMBER; RV.val.num = sysvar(t,TV.val.num,x);
}

void wmunge(flag)			/* update flags for all windows */
{
  register Window *wp;

  for (wp = first_window; wp; wp = wp->nextw) wp->w_flag |= flag;
}

static int sysvar(n,value,set) int n, set; int32 value;
{
  extern int
    beeper,		/* in main.c */
    case_fold,		/* in search.c */
    cc_trigger,		/* in mline.c */
    gimmehelp,		/* bind.c */
    overstrike,		/* in random.c */
    hstep,		/* in display.c */
    tcolor, mcolor, t_nrow, t_ncol;
  int z = -1, *x = &z;	/* z in case of booboo */

  switch (n)
  {
    case  5:						/* case-fold-search */
      x = &case_fold;
      if (set) fix_cmap((int)value);
      break;
    case  1: x = &gimmehelp; break;				    /* HELP */
    case  2:						      /* overstrike */
      x = &overstrike;
      if (set && value != overstrike)	       /* update all the mode lines */
	wmunge(WFMODE);
      break;
    case  4:						   /* screen-length */
      if (set) display_resized((int)value, t_ncol);
      return t_nrow +1;
    case 12:						    /* screen-width */
      if (set) display_resized(t_nrow +1, (int)value);
      return t_ncol;
    case 13:					       /* horizontal-scroll */
      x = &hstep;
      if (set && value == 0)
	  { onlywind(FALSE,1); curwp->lmargin = 0; wmunge(WFHARD); }
      break;
    case  6: x = &curbp->tabsize;  break;		       /* tab-stops */
    case  7: x = &curbp->wrap_col; break;		       /* word-wrap */
    case  8:					      /* (text-color color) */
      x = &tcolor; if (set) screen_is_garbage = TRUE;
      break;
    case  9:					  /* (modeline-color color) */
      x = &mcolor; if (set) screen_is_garbage = TRUE;
      break;
    case 11: x = &beeper; break;				/* (beeper) */
    case  3: x = &cc_trigger; break;			    /* complete-key */
  }
  if (set) *x = value;
  return *x;
}
