#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/syslog.h>
#include <pcre.h>

#define MAXSIZE 60
static char which[] = "/usr/bin/which '%s'\n";

#define OVECCOUNT 30    /* should be a multiple of 3 */
int check_expression(char *str) {
	int rc;
	pcre *re; /* Our regular expression */
	int ovector[OVECCOUNT];
	const char *error;
	int erroffset;
	/* Check the regular expression */
	re = pcre_compile(
		"^[A-Za-z0-9]+[A-Za-z0-9\\.\\-]*$",              /* the pattern */
		0,                    /* default options */
		&error,               /* for error message */
		&erroffset,           /* for error offset */
		NULL);                /* use default character tables */

	/* Compilation failed: print the error message and exit */

	if (re == NULL)
	{
	    printf("PCRE compilation failed at offset %d: %s\n", erroffset, error);
	    return 1;
	}

	rc = pcre_exec(
		re,                   /* the compiled pattern */
  	        NULL,                 /* no extra data - we didn't study the pattern */
		str,              /* the subject string */
		(int)strlen(str), /* the length of the subject */
		0,                    /* start at offset 0 in the subject */
		0,                    /* default options */
		ovector,              /* output vector for substring information */
		OVECCOUNT);           /* number of elements in the output vector */
/* Matching failed: handle error cases */

	if (rc < 0)
	{
		switch(rc)
		{
			case PCRE_ERROR_NOMATCH: printf("Sorry, that's not a valid command name\n");  break;
			default: printf("Sorry, there was a matching error %d\n", rc); break;
		}
		return 1;
	}

	/* Match succeded */
#ifdef DEBUG
	printf("PCRE match succeeded\n");
#endif
	return 0;
}

/* Change all \n chars to \0 
 * Careful: this function does not work if str is not \0 terminated */
void remove_eol(char *str) 
{
	char *p;
	if ( str == NULL ) 
		return;

	for (p = str; *p != '\0'; p++) {
		if ( *p == '\n' ) {
			*p = '\0';
		}
	}
}

int main(int argc, char *argv[]) 
{
	char *buf;
	char *cmd;
	buf = malloc(MAXSIZE);
	/* Maximum length for cmd */ 
	cmd = malloc(MAXSIZE+18);
	if ( buf == NULL  || cmd == NULL ) {
		perror(argv[0]);
		exit(1);
	}
	memset(buf, 0, MAXSIZE);
	printf("Which command are you looking for? ");
	buf = fgets(buf, MAXSIZE, stdin); /* Notice that buf will get the EOL too */
	remove_eol(buf);
	printf("\n");
	if ( buf == NULL ) {
		perror(argv[0]);
		exit(1);
	}
	
	if ( check_expression(buf) != 0 ) 
		exit(1);

	printf ("Looking for '%.100s'\n", buf);
	sprintf(cmd, which, buf); /* Cmd is bigger than buf, it should hold*/
	syslog(36, "Looking for '%.100s'", cmd); /* We don't output all the command and we use a proper format string */

	printf ("The command you are looking for is: \n");
	if (system(cmd) != 0 )  {
		printf ("ERR - Sorry I did not find that command\n");
		exit(1);
	}
		
	exit(0);
}
