/*    National Enquirer To Buy Hamburger Chain              */
/*    ..."We were really famished.", says top Exec.         */

/*******************************************************
  This program prints random National Enquirer type
  headlines. It was inspired by a database that appeared
  on the Net somewhere, but without the driver program.
  This is my first program in C, so have mercy on some
  of the code and casting overkill.
    The database should be in the current directory under
        the name <filename> (defined below). This database may be edited
        quite freely. Capitalized words result in subsearches
        of the dbase until the complete headline is decoded.
        The first string searched is "CODE", which calls up the
        main template, usually "CONST\\", which forms the main
        headline template. 
  Have fun with this. It is a little slow on the searches. 
  A way out of this would be to use a table file which determines
  how many strings are in each category--to set the random
  number range limits for fetches, but this would require 
  running the table maker to ensure that the data was uptodate in
  case the string database had been edited.

      Bob Dickow, Lionel Hampton School of Music, U of Idaho,
          Moscow, ID 83843

          (...egg-id!ui3!dickow)

***************************************************************/
#include <stdio.h>
#include "errno.h"
#include "ctype.h"

#define BOOLEAN     char   /* for True/False checking */
#define MAXBUFF     81     /* a buffer size for parsing various strings */
#define MAXHDLN     300    /* sets size of headline assemble buffer  */
#define NL          0x0a   /* ascii 10 for newline character */
#define IOERR       -1     /* flags file io error */
#define NOTFOUND    -2     /* flags something not located */
#define EQUAL       0      /* synonym. used as ok flag or equivalency */
#define BUFFLIMIT 200 /* Max size of string work buffers in parse() */
#define KEYLIMIT  100 /* Max size of Key_buff in parse() rtn     */

char *filename = "headlines.txt"; /* database file */
char *seekstart_str = "CODE"; /* first str to seek in file */
char hdln_buff[MAXHDLN]; /* headline assembled here  */

/* prcnt_chck checks to see if first chr in passed string (pointer) is
   a '%' and returns TRUE (boolean) if so, FALSE otherwise           */

BOOLEAN prcnt_chck(buffptr)
char *buffptr;
{
   if (*buffptr == (char) '\%') 
     return (BOOLEAN) 1;
   else
     return (BOOLEAN) 0;
}         /* end prcnt_flg()    */


/* randomize is a routine to randomize the rnd num generator seed.
   This method is probably system dependent. */

void randomize()
{
  unsigned int rtime;

  rtime = (unsigned int) time(NULL);
  (void) srand(rtime);
}           /* end randomize()  */

/* replace NL char with NULL char given pointer to string */

void nullput(ptr)
char *ptr;
{
  char *buff = ptr;

  while ((*buff != (char) NL) && (buff++ - ptr)<MAXBUFF-1);
  *buff = (char) NULL;
}                 /* end nullput()  */


/* find_category locates a category identifier & returns 0 if ok, -2 if not 
   found, or -1 if error. The position will be located at the byte just
   past the string. The file handle must be previously opened.  */

int find_category(handle,string) 
FILE *handle;     
char *string;
{
  BOOLEAN prcnt_flg, last_flg;
  char buffer[MAXBUFF];  /* for temporary storage */

  if (fseek(handle,0L,0) != 0)   /* set file pos to beginning of file */
        return IOERR;
  last_flg = (BOOLEAN) 0;
  while (fgets(buffer,MAXBUFF-1,handle) != NULL) {

    (void) nullput(buffer);
        prcnt_flg = prcnt_chck(buffer);
    if ((strcmp(buffer,string)==EQUAL) && (last_flg==1))
          return EQUAL;
    last_flg = prcnt_flg;
  }
  if (ferror(handle)) {
      printf ("I/O ERROR #%d\n",errno);
          exit();
  }
  return (int) NOTFOUND;
}            /* end find_category()  */

/* returns a pointer to a buffer which is set to random string */
/* this routine changes buff which is a pointer passed to it   */

char *rand_str(handle,buff)
FILE *handle;
char *buff;
{
  long ftell();

  char buffer[MAXBUFF]; /* working buffer local to function */
  int count = 0;        /* number of lines input till '%' chr matched */
  long startloc;        /* saves current location in file at entry */
  int rand_index;       /* set to random # bet 0 and # of lines in categ. */

  startloc = ftell(handle);

  do {
    (void) fgets(buffer,MAXBUFF-1,handle);
    (void) nullput(buffer);
    count++;
  }
  while (prcnt_chck(buffer)==0);  /* end of do loop */

  if (--count == 0) 
    return (char *) NULL;

  (void) randomize();
  rand_index =  (rand() % count)+1;
  if (fseek(handle,startloc,0) != 0)
    return (char *) NULL;
  for (count=0; count<rand_index; count++)
    (void) fgets(buffer,MAXBUFF-1,handle);
  (void) nullput(buffer);
  (void) strcpy(buff,buffer,MAXBUFF-1);
  return (char *)buff;
}         /* end rand_str()  */


/*  parse() actually takes the CONST line and parses it, extracting capital-
    ized words and sub-searching the file. The headline is assembled in
        hdln_buff. str is the CONST line, and the routine returns a pointer to
        hdln_buff.  */

char *parse(handle,str,hdln_str)
FILE *handle;
char * str, * hdln_str;

{
  int ind=0, key_ind=0, hd_ind=0;
  char buff1[BUFFLIMIT], buff2[BUFFLIMIT], key_buff[KEYLIMIT],
       found_str[KEYLIMIT];
  char *temp_str,  *str2 = buff2;
  unsigned char chr;
  int returncode; 
  char * strcat(); /* keep the compiler happy about types */

  (void) strcpy(buff1,str);
  str = buff1;

  *key_buff = (char) NULL;

  while ( *(str + ind) != (char) NULL ) {
    if ( isupper( *(str+ind) ) )  {
          *(key_buff) = (char) NULL;
          key_ind = 0;
          while ( isupper( *(str+ind)) || isdigit( *(str+ind) ) ) {
            *(hdln_str + hd_ind) = *(key_buff+key_ind) = *(str+ind);
                ind++; key_ind++; hd_ind++;
            if (key_ind == KEYLIMIT) {
                  printf ("\nOverflow error\n");
                  exit();
                }
          }
          *(key_buff + key_ind) = (char) NULL;
        }
        if ( strlen(key_buff) > 1) {
          /* search */
          returncode = find_category(handle,key_buff);

      if (returncode == EQUAL) {
                (void) rand_str(handle,found_str);
                hd_ind -= strlen(key_buff);
          } 
          else if (returncode == NOTFOUND)
        *found_str = (char) NULL;
      if ((returncode == EQUAL) || (returncode == NOTFOUND)) {
                *(key_buff) = *(hdln_str + hd_ind) = (char) NULL;
        (void) strcpy( str2, found_str ); 
      }
      if ( (strlen(str2) + strlen(found_str)) <= BUFFLIMIT)
       temp_str = strcat( str2, str+ind );
           else {
                  printf ("\nOverflow error\n");
                  exit();
       }
        str2 = str;
                str = temp_str;
        ind = key_ind = 0;   /* reset indices into buffers */
         }   
    else {
          chr = *(str+ind++);
          if (chr == (char) '|') {
            if (*(str+ind) == (char) 's') {
          if (*(hdln_buff+hd_ind-1) == (char) 'y') {
                    *(hdln_buff+hd_ind-1) = (char) 'i';
            *(hdln_buff+hd_ind++) = (char) 'e';
                  }
                  else if (*(hdln_buff+hd_ind-1) == (char) 'o') 
                   { *(hdln_buff+hd_ind++) = (char) 'e'; }
                  else if ((*(hdln_buff+hd_ind-1) == (char) 'h') 
                       && ((*(hdln_buff+hd_ind-2) == (char) 's') 
                           || (*(hdln_buff+hd_ind-2) == (char) 'c'))) {
                    if (*(hdln_buff+hd_ind-3) == (char) 'i') 
                          hd_ind = hd_ind-3;
                    else
                     *(hdln_buff+hd_ind++) = (char) 'e';
                  }
                }
                 else if (*(str+ind) == (char) 't') {
                  if (*(hdln_buff+hd_ind-2) == (char) 'v')
                    *(hdln_buff+hd_ind-- -2) = (char) 'f';
            }
                         chr = (char) *(str+ind++); 
          }
          if (chr == (char) '\\' )
            chr = (char) NL;
      if (hd_ind < MAXHDLN-1)
            *(hdln_str+hd_ind++) = chr;
          else {
            printf ("\nOverflow error\n");
            exit();
        }
        }
  }
*(hdln_str+hd_ind) = (char) NULL;
return ((char *)hdln_str);
} /* end parse() */


main()
{
  FILE *handle;

  handle = fopen(filename,"r");
  if (handle != (FILE *) NULL) {
        if ( parse(handle,seekstart_str,hdln_buff) != (char *) NULL)
          printf ("%s\n",hdln_buff);
    else if (ferror(handle))
      printf ("I/O ERROR #%d\n",errno);
    if (handle != (FILE *) NULL)
      fclose(handle);
  }
  else
    printf ("%s not found\n",filename);
}        /* end main() */
