/**********************************************************************/
/*   This  is  an  implementation  of  the  standard  'man'  command  */
/*   implemented  as  a  macro  so  we can look at manual pages from  */
/*   within  crisp.  Also,  because  the  'man' implementation under  */
/*   Interactive  unix  is non-standard and almost unusable (can not  */
/*   have private manual pages).				      */
/**********************************************************************/

# include	"crisp.h"

# define	MANPATH	"/usr/catman:/usr/man:/usr/local/man"

void
man()
{	string	manpath;
	declare entry;
	int	argc;
	list	paths;
	int	i;
	int	curbuf;
	int	entries_found = 0;
	string	section = "";

	curbuf = inq_buffer();
	manpath = getenv("MANPATH");
	if (manpath == "")
		manpath = MANPATH;
	
	paths = split(manpath, ":");

	for (argc = 0; ; argc++) {
		/***********************************************/
		/*   Get   next  argument.  If  argument  not  */
		/*   specified,  and  its the first argument,  */
		/*   then   prompt   user.   Otherwise  we've  */
		/*   finished scanning the argument list.      */
		/***********************************************/
		if (get_parm(argc, entry) <= 0) {
			if (argc)
				break;
			entry = "";
			if (get_parm(0, entry, "Manual entry: ", NULL, "") <= 0)
				return;
			}
		if (is_integer(entry)) {
			sprintf(section, "%d", entry);
			continue;
			}

		if (strlen(entry) == 1 && index("12345678nl", entry)) {
			section = entry;
			continue;
			}		
		for (i = 0; i < length_of_list(paths); i++) {
			if (man_entry(paths[i], section, entry) < 0)
				break;
			}
		if (i < length_of_list(paths))
			break;
		}

	if (entries_found)
		message("");
	else
		error("Manual entry '%s' not found.", entry);
}
int
man_entry(string path, string section, string entry)
{
	list	files;
	int	j, k, ret;
	string	f, s, s1;
	string	dir, current_dir;
	int	buf;
	int	win;
	list	l;
	int	sysv_man;
	extern int entries_found;
	extern int curbuf;

	/***********************************************/
	/*   BSD  manual  pages  are  one  level deep  */
	/*   directories.  SysV  ones  are  two level  */
	/*   deep,  and  also  the naming conventions  */
	/*   are  different,  e.g.  man1/tty.1  means  */
	/*   its a pre-formatted manual page.	       */
	/***********************************************/
	sysv_man = FALSE;
	files = file_glob(path + "/*" + section + "/" + entry + ".*");
	if (length_of_list(files) == 0) {
		sysv_man = TRUE;
		files = file_glob(path + "/*/*" + section + "/" + entry + ".*");
		}
	for (j = 0; j < length_of_list(files); ) {
		f = files[j++];
		/***********************************************/
		/*   Break   the   filename   up   into   its  */
		/*   components    because    we   want   the  */
		/*   filename  part  and  the  last directory  */
		/*   name part.				       */
		/***********************************************/
		l = split(f, "/");
		k = length_of_list(l);
		s = l[k-2];
		s1 = l[k-1];
		if (substr(s1, strlen(s1) - 1) == ".z") {
			message("Unpacking " + l[k-1] + " ...");
			buf = perform_unix_command(
				"pcat " + f + " | sed 's/.\010//g' | sed 's/^        //' ", f);
			}
		else if (substr(s1, strlen(s1) - 1) == ".Z") {
			message("Uncompressing " + l[k-1] + " ...");
			buf = perform_unix_command(
				"zcat <" + f + " | sed 's/.\010//g'", f);
			}
		else if (sysv_man) {
			message("Reading %s", f);
			buf = create_buffer(entry, f, TRUE);
			set_buffer(buf);
			re_translate(SF_GLOBAL, "^        ", "");
			top_of_buffer();
			re_translate(SF_GLOBAL, "_\x08", "");
			}
		else if (substr(s, 1, 3) == "man") {
			message("Formatting " + l[k-1] + " ...");
			/***********************************************/
			/*   Go  to  the  directory  above this entry  */
			/*   in   order  for  the  includes  to  work  */
			/*   properly.				       */
			/***********************************************/
			k = rindex(f, "/");
			getwd(NULL, current_dir);
			if (k > 0) {
				dir = substr(f, 1, k-1);
				k = rindex(dir, "/");
				if (k > 0) {
					dir = substr(dir, 1, k-1);
					{string ss = dir; cd(ss);}
					f = substr(f, strlen(dir) + 2);
					}
				}
			buf = perform_unix_command(
				"nroff -man " + f + " | sed 's/.\010//g'", f);
			cd(current_dir);
			}
		else if (substr(s, 1, 3) == "cat") {
			buf = perform_unix_command(
				"sed 's/_\010//g' < " + f, f);
			}
		entries_found++;
		message("<Esc> to exit. <Enter> next entry.");
		win = sized_window(inq_lines(buf), inq_line_length(buf) + 1, "");
		
		ret = select_buffer(buf, win, SEL_NORMAL, man_keys());
		delete_buffer(buf);
		set_buffer(curbuf);
		attach_buffer(curbuf);
		if (ret < 0)
			return -1;
		if (section != "")
			break;
		}
	return 0;

}

void
man_keys()
{
	assign_to_key("<Alt-S>", "search__fwd");
	assign_to_key("<Alt-Y>", "search__back");
	assign_to_key("<F5>", "search__fwd");
	assign_to_key("<F6>", "translate__fwd");
	assign_to_key("<Shift-F5>", "search_next");
	assign_to_key("<Keypad-5>", "search_next");
	assign_to_key("<Shift-F6>", "search_prev");
	assign_to_key("<Alt-N>", "search_prev");
}
/**********************************************************************/
/*   Function  to  return a list of directories contained within the  */
/*   directory passed as an argument.				      */
/**********************************************************************/
list
get_dirs(string dir)
{	list	l = NULL;
	string	name;
	int	mode;
	
	file_pattern(dir + "/*");
	
	while (find_file(name, NULL, NULL, NULL, mode)) {
		if (mode & S_IFDIR)
			l += name;
		}
	return l;
}

/**********************************************************************/
/*   Macro to display output of unix 'apropos' command in a window.   */
/**********************************************************************/
void
apropos(string entry)
{
	int	cur_buf;
	int	win;
	int	ret;
	int	apr_buf;
	string	line;	
	string	section;
	string	ent;

	if (entry == "") {
		error ("Usage: apropos entry");
		return;
		}
	
	cur_buf = inq_buffer();
	apr_buf = perform_unix_command("apropos " + entry, "Apropos-Buffer");
	message("Hit <Enter> to see manual pages.");
	win = sized_window(inq_lines(apr_buf) + 1, inq_line_length(apr_buf) + 2);
	ret = select_buffer(apr_buf, win);
	if (ret < 0) {
		delete_buffer(apr_buf);
		return;
		}
	set_buffer(apr_buf);
	goto_line(ret);
	line = trim(read());
	delete_buffer(apr_buf);
	set_buffer(cur_buf);
	attach_buffer(cur_buf);

	ret = re_search(NULL, "[, (]", line);
	if (ret) {
		ent = substr(line, 1, ret - 1);
		ret = index(line, "(");
		if (ret) {
			section = substr(line, ret + 1, 1);
			message("man %s %s ...", section, ent);
			man(section, ent);
			}
		else {
			message("man %s ...", ent);
			man(ent);
			}
		}
}
