/* wscr	 Copyright(c) 1998
 * by Eddie Buckley <eddie@sjfn.nb.ca>
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation.  No representations are made about the suitability of this
 * software for any purpose.  It is provided "as is" without express or 
 * implied warranty.
 */

/* Inspried by permute2.c by Jon Guthrie from snippets */

#include    <stdio.h>
#include    <stdlib.h>
#include    <string.h>
#include    <unistd.h>
#include    <ctype.h>
#include    <errno.h>
#include    "wscr.h"

int
main(int argc, char **argv)
{
    size_t     length;
    char    opt = '\0', arg;

    progname = ((strrchr(argv[0], '/'))
                            ? (strrchr(argv[0], '/')+1) : argv[0]);
    if (2 > argc)
    {
        fprintf(stderr, "Usage: %s: [options] <string>\n", progname);
        exit(1);
    }
    while((arg = getopt(argc, argv, "dhw:")) != -1 && opt == '\0')
    {
        switch(arg)
        {
            case    '\0':
                break;
            case    'd':
                flags += DICT;
                wordlistfile = defaultfile;
                break;
            case    'w':
                flags += DICT;
                wordlistfile = optarg;
#ifdef	DEBUG
                printf("%s\n", optarg);
#endif
                break;
            case    'h':
                help();
                break;
            default:
                break;
        }
        if(opt == '\0') opt = arg;
    }

    if(argv[optind]==NULL)
    {
        fprintf(stderr, "%s: missing text string\n", progname);
        exit(1);
    }

    length = strlen(argv[optind]);

    if(flags & DICT)
    {
        qsort(argv[optind], length, sizeof(char),
                    (int(*)(const void *, const void *))charcasecmp);
        sortlist(argv[optind]);
        return	0;
    }
    /* It only works if they're printed in order */
    qsort(argv[optind], length, sizeof(char),
                    (int(*)(const void *, const void *))charcmp);

#ifdef  DEBUG
    printf("array = %s\n", argv[optind]);
#endif

    permute(argv[optind], 0, length);
    return 0;
}


/*
**  This function prints all of the permutations of string "text"
**  (which has length "len") starting at "start."
*/

void
permute(char *text, int start, int len)
{
    int     i;
    char   *str;

    if(start < len)
    {
        if(NULL == (str = malloc(len)))
        {
            fprintf(stderr, "%s: %s\n", progname, strerror(errno));
            exit(0);
        }

        strcpy(str, text);
        for(i=start; i<len; ++i)
        {
            int     temp;

            if( (i == start) || ( *(str+i) != *(str+start) ))
            {   /* For each character that's different   *
                 * Swap the next first character with    *
                 * the current first                     *
                 */
                temp = *(str+i);
                *(str+i) = *(str+start);
                *(str+start) = temp;
	        /* Recurse! Recurse!! Recurse!!! */
                permute(str, start+1, len);
            }
        }
        free(str);
    }
    else
        printf("%s\n", text);
}


int
charcmp(char *ch1, char *ch2)
{
    return(*ch1 - *ch2);
}

int
charcasecmp(char *ch1, char *ch2)
{
/* Case-insensitive version of above */
    return(tolower(*ch1) - tolower(*ch2));
}

void
sortlist(char *text)
{
    FILE    *wordlist;
    char    *buf, *buf2;
    size_t  length, textlength;

    if((wordlist = fopen(wordlistfile, "r"))==NULL)
    {
        fprintf(stderr, "%s: %s: %s\n", progname, wordlistfile,
                                                        strerror(errno));
        exit(2);
    }
    if((buf = calloc(1024, sizeof(char)))==NULL)
    {
        fprintf(stderr, "%s: %s:\n", progname, strerror(errno));
        exit(3);
    }
    textlength = strlen(text);
    for(;;)
    {
        fscanf(wordlist, "%s", buf);
        if(feof(wordlist))
            break;
        if(ferror(wordlist))
        {
            fprintf(stderr, "%s: %s: %s\n", progname, wordlistfile,
                                                        strerror(errno));
            exit(2);
        }
        if((buf2 = strdup(buf))==NULL)
        {
            fprintf(stderr, "%s: %s\n", progname, strerror(errno));
            exit(3);
        }
        length = strlen(buf2);
        if(length == textlength)
        {
            qsort(buf2, strlen(buf2), sizeof(char),
                       (int(*)(const void *, const void *))charcasecmp);
            if(tolower(*text) == tolower(*buf2))
                if(!strcasecmp(text, buf2))
                    printf("%s\n", buf);
        }
    }
    fclose(wordlist);
    free(buf);
    free(buf2);
    return;
}

void
help(void)
{
    printf("%s version %s Copyright(c) 1998 ", progname, ver);
    printf("by Eddie Buckley <eddie@sjfn.nb.ca>\n");
    printf("Usage: %s [OPTION] <text>\n", progname);
    printf("Print permutations of strings\n\n");
    printf("  -d \t\tcheck permutations against /usr/dict/words\n");
    printf("%s%s\n", "  -w <filename>\tcheck permutations against user ",
           "specified wordlist file");
    printf("  -h \t\tprint this help\n\n");
    printf("  With no options specified, %s will print all ", progname);
    printf("permutations of <text>\n\n");
    printf("Options are mutually exclusive, so only the first option is honored\n");
    exit(0);
}

