/*
 *	unix man(1) clone
 *	john aycock, 1990
 */

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>

#define DFLT_PAGER	"more"
#define DFLT_MANDIR	"man:"
#define DFLT_MANIDX	"man:.manidx"
#define MAXIDXLINE	512
#define MAXALIASES	8
#define MAXBUFFER	254
#define LINELENGTH	77
#define	VERSION		"1.0"
#define VOID		void

#define TRUE		(1)
#define FALSE		(!TRUE)
typedef char bool;

struct line {
    char *aliases[MAXALIASES];
    char *desc, *fname;
};

bool keyword = FALSE;
char *progname, *name;

bool wildcard (s, wc)
char *s, *wc;
{
    bool ok;

    while (*s && *wc) {
	switch (*wc) {
	    case '?':	wc++, s++;  break;
	    case '*':	if (!*++wc) return (TRUE);
			while (*s && !(ok = wildcard (s, wc))) s++;
			return (bool) (ok ? TRUE : FALSE);
	    default:	if (*wc++ != *s++) return (FALSE);
	}
    }
    return (bool) (!*s && !*wc ? TRUE : FALSE);
}

struct line *getline (fp)
FILE *fp;
{
    int i;
    register char *p;
    static char buffer[MAXIDXLINE];
    static struct line l;

    while (1) {
	if (fgets (buffer, MAXIDXLINE-1, fp) == NULL) return (NULL);
	if (*(buffer + strlen (buffer) - 1) != '\n') return (NULL);
	for (p = buffer; *p != '\n' && isspace (*p); p++) ;
	if (*p != '\n' && *p != '#') break;
    }
    for (i = 0; i < MAXALIASES; i++) l.aliases[i] = NULL;
    l.desc = l.fname = NULL;
    for (i = 0; i < MAXALIASES; i++) {
	l.aliases[i] = p;
	while (*p != '\n' && *p != '|' && *p != ':') p++;
	if (*p == '\n') return (NULL);
	else if (*p == ':') {
	    *p++ = '\0'; break;
	}
	*p++ = '\0';
    }
    l.desc = p;
    while (*p != '\n' && *p != ':') p++;
    if (*p == '\n') return (NULL);
    *p++ = '\0';  l.fname = p;
    while (*p++ != '\n') ;  *p = '\0';
    return (&l);
}

VOID printit (l)
struct line *l;
{
    int i, len = 0;

    for (i = 0; i < MAXALIASES && l->aliases[i]; i++) {
	len += printf ("%s%c", l->aliases[i], (i<MAXALIASES-1&&l->aliases[i+1]) ? ',' : ':');
    }
    printf ("%*.*s\n", LINELENGTH-len, LINELENGTH-len, l->desc);
}

VOID main (argc, argv)
int argc;
char *argv[];
{
    int i;
    char buffer[MAXBUFFER+1];
    bool found = FALSE;
    struct line *line;
    FILE *mindex;

    if ((progname = strrchr (argv[0], '/')) == NULL) {
	if ((progname = strrchr (argv[0], ':')) == NULL) progname = argv[0];
	else progname++;
    } else progname++;

    if (argc < 2) {
	fprintf (stderr, "usage: %s <name>\n", progname);
	fprintf (stderr, "       %s -k <keyword>\n", progname);
	fprintf (stderr, "       %s -v\n", progname);
	exit (0);
    }
    if (!strcmp (argv[1], "-v")) {
	fprintf (stderr, "%s: unix man(1) clone version %s . john aycock . 1990\n", progname, VERSION);
	exit (0);
    } else if (!strcmp (argv[1], "-k")) {
	if (argc != 3) {
	    fprintf (stderr, "%s: syntax error (\"%s\" for help)\n", progname, progname);
	    exit (1);
	}
	keyword = TRUE;  name = argv[2];
	strcpy (buffer, "*");  strcat (buffer, name);  strcat (buffer, "*");
    } else {
	if (argc != 2) {
	    fprintf (stderr, "%s: syntax error (\"%s\" for help)\n", progname, progname);
	    exit (1);
	}
	name = argv[1];
    }

    if ((mindex = fopen (DFLT_MANIDX, "r")) == NULL) {
	fprintf (stderr, "%s: unable to open %s\n", progname, DFLT_MANIDX);
	exit (1);
    }

    while (!feof (mindex)) {
	if ((line = getline (mindex)) == NULL) {
	    if (feof (mindex)) break;
	    fprintf (stderr, "%s: error reading %s\n", progname, DFLT_MANIDX);
	    exit (1);
	}
	if (!keyword) {
	    for (i = 0; i < MAXALIASES && line->aliases[i]; i++) {
		if (!strcmp (line->aliases[i], name)) {
		    found = TRUE;
		    strcpy (buffer, DFLT_PAGER);  strcat (buffer, " ");
		    if ((*line->fname == '@') || !strpbrk (line->fname, ":/")) strcat (buffer, DFLT_MANDIR);
		    if (*line->fname == '@') line->fname++;
		    strcat (buffer, line->fname);
		    if (system (buffer) < 0) {
			fprintf (stderr, "%s: error invoking %s on manual page\n", progname, DFLT_PAGER);
			exit (1);
		    }
		    break;
		}
	    }
	    if (found) break;
	} else {
	    for (i = 0; i < MAXALIASES && line->aliases[i]; i++) {
		if (wildcard (line->aliases[i], name)) {
		    found = TRUE;  printit (line);  goto end;
		}
	    }
	    if (wildcard (line->desc, buffer)) {
		found = TRUE;  printit (line);
	    }
end:
	}
    }

    if (!found) fprintf (stderr, "%s: nothing appropriate\n", progname);
    fclose (mindex);
    exit (0);
}
