/**************************************************************
 *
 *	CRISP - Custom Reduced Instruction Set Programmers Editor
 *
 *	(C) Paul Fox, 1989, 1990, 1991
 *
 *    Please See COPYRIGHT notice.
 *
 **************************************************************/
# include	"list.h"

/**********************************************************************/
/*   Head of the list of current bookmarks.			      */
/**********************************************************************/
Head_p	hd_books;

/**********************************************************************/
/*   What a bookmark looks like.				      */
/**********************************************************************/
typedef struct bookmark_t {
		long		b_id;	/* Bookmark number.		*/
		u_int16		b_buffer;
		int		b_line;
		int		b_col;
		} bookmark_t;
bookmark_t	*find_bookmark PROTO((long, int));
		
void
init_bookmarks()
{
	hd_books = ll_init();
}
void
drop_bookmark()
{	bookmark_t	*bk;
	char	*cp = get_str(2);
	int	new_bookmark = FALSE;
	
	acc_assign_int((long) 0);
	bk = find_bookmark(argv[1].l_int, FALSE);
	/***********************************************/
	/*   If   bookmark   already   defined   then  */
	/*   prompt  user  (if  necessary)  to see if  */
	/*   we need to overwrite it.		       */
	/***********************************************/
	if (bk) {
		if (*cp != 'y' && *cp != 'Y' &&
		    eyorn("Overwrite existing bookmark") != TRUE) {
			return;
			}
		}
	else {
		/***********************************************/
		/*   Otherwise create one.		       */
		/***********************************************/
		bk = find_bookmark(argv[1].l_int, TRUE);
		new_bookmark = TRUE;
		}
	if (argv[3].l_flags == F_INT && argv[4].l_flags == F_INT &&
	    argv[5].l_flags == F_INT) {
		bk->b_buffer = argv[3].l_int;
		bk->b_line = argv[4].l_int;
		bk->b_col = argv[5].l_int;
		}
	else {
		bk->b_buffer = curbp->b_bufnum;
		bk->b_line = *cur_line;
		bk->b_col = *cur_col;
		}
	if (new_bookmark)
		ll_append(hd_books, (char *) bk);
	infof("Bookmark dropped.");
	acc_assign_int((long) 1);	
}
/**********************************************************************/
/*   Function to destroy a bookmark.				      */
/**********************************************************************/
void
delete_bookmark()
{	register List_p	lp;
	bookmark_t	*bk = NULL;
	long	book_no = argv[1].l_int;

	for (lp = ll_first(hd_books); lp; lp = ll_next(lp)) {
		bk = (bookmark_t *) ll_elem(lp);
		if (bk->b_id == book_no)
			break;
		}
	if (lp == NULL)
		return;
	ll_delete(lp);
	chk_free((void *) bk);
}
void
goto_bookmark()
{
	bookmark_t	*bk;
	int	move = TRUE;
	long	book_no;
	LISTV	*saved_argv;
	
	acc_assign_int(0L);
	/***********************************************/
	/*   Save  arguments  to this function before  */
	/*   calling    get_iarg1()    because    the  */
	/*   command   completion   macros   may  get  */
	/*   called and destroy our argument vector.   */
	/***********************************************/
	saved_argv = argv;
	if (get_iarg1("Go to bookmark: ", &book_no))
		return;
	argv = saved_argv;

	bk = find_bookmark(book_no, FALSE);
	if (bk == NULL) {
		return;
		}

	if (argv[2].l_flags != F_NULL) {
		move = FALSE;
		int_assign(argv[2].l_sym, (long) bk->b_buffer);
		}
	if (argv[3].l_flags != F_NULL) {
		move = FALSE;
		int_assign(argv[3].l_sym, (long) bk->b_line);
		}
	if (argv[4].l_flags != F_NULL) {
		move = FALSE;
		int_assign(argv[4].l_sym, (long) bk->b_col);
		}

	if (move) {
		WINDOW	*wp;
		/***********************************************/
		/*   If  current  buffer  doesn't  match  the  */
		/*   bookmark  then  look  for  a window with  */
		/*   the bookmark on display.		       */
		/***********************************************/
		if (bk->b_buffer != curbp->b_bufnum) {
			for (wp = wheadp; wp; wp = wp->w_wndp)
				if (wp->w_bufp->b_bufnum == bk->b_buffer)
					break;
			if (wp == NULL) {
				BUFFER	*bp = numberb(bk->b_buffer);
				if (bp == NULL) {
					ewprintf("goto_bookmark: no such buffer.");
					return;
					}
				showbuffer(bp, curwp);
				curbp = bp;
				}
			else {
				curwp = wp;
				curbp = curwp->w_bufp;
				}
			}
		set_hooked();
		argv[1].l_int = bk->b_line;
		argv[2].l_int = bk->b_col;
		move_abs();
		}
	acc_assign_int(1L);
}
/*******************************************************************/
/*   Create a list containing all currently defined bookmarks.	   */
/*******************************************************************/
void
bookmark_list()
{	int	size = 0;
	register List_p	lp;
	bookmark_t	*bk;
	LIST	*new_list;
	int	new_len;
	register LIST	*nlp;
	ref_t	*rp;
	
	/***********************************************/
	/*   Find  out  how  long  the list is, so we  */
	/*   know how much memory to allocate.	       */
	/***********************************************/
	for (lp = ll_first(hd_books); lp; lp = ll_next(lp)) {
		size++;
		}
	if (size == 0) {
		acc_assign_null();
		return;
		}
		
	/***********************************************/
	/*   Allocate memory.			       */
	/***********************************************/
	new_len = size * (sizeof_atoms[F_INT] * 4) + sizeof_atoms[F_HALT];
	new_list = (LIST *) chk_alloc(new_len);
	if (new_list == NULL) {
		acc_assign_null();
		return;
		}
	nlp = new_list;
	/***********************************************/
	/*   Now fill in the list.		       */
	/***********************************************/
	for (lp = ll_first(hd_books); lp; lp = ll_next(lp)) {
		bk = (bookmark_t *) ll_elem(lp);
		*nlp = F_INT;
		LPUT32(nlp, bk->b_id);
		nlp += sizeof_atoms[F_INT];
		*nlp = F_INT;
		LPUT32(nlp, (long) bk->b_buffer);	
		nlp += sizeof_atoms[F_INT];
		*nlp = F_INT;
		LPUT32(nlp, (long) bk->b_line);	
		nlp += sizeof_atoms[F_INT];
		*nlp = F_INT;
		LPUT32(nlp, (long) bk->b_col);	
		nlp += sizeof_atoms[F_INT];
		}
	*nlp = F_HALT;
	rp = r_init(F_RLIST, (char *) new_list, new_len);
	acc_assign_ref(rp);
	r_dec(rp);
	
}
/**********************************************************************/
/*   Find  the  bookmark  associated  with a bookmark ID. If flag is  */
/*   TRUE then create it if not already defined.		      */
/**********************************************************************/
bookmark_t *
find_bookmark(id, flag)
long	id;
int	flag;
{	register List_p	lp;
	bookmark_t	*bk;
	
	for (lp = ll_first(hd_books); lp; lp = ll_next(lp)) {
		bk = (bookmark_t *) ll_elem(lp);
		if (bk->b_id == id)
			return bk;
		}
	if (!flag)
		return NULL;
	bk = (bookmark_t *) chk_alloc(sizeof(bookmark_t));
	bk->b_id = id;
	bk->b_buffer = 0;
	bk->b_line = 0;
	bk->b_col = 0;
	return bk;
}
