/*
  Sample solution to CS574, Fall 2005 HW1

  Maps a file into a memory buffer and counts occurrences of the string "<h"

*/

#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>

#define MAPFILE "/home/vip1/pfeiffer/classes/574/sem/f05/hw/hw1.php"

/*
  When I repeated this crash() code three times in main(), I realized
  it was time to make a procedure out of it
*/
void crash(char *place)
{
    perror(place);
    exit(EXIT_FAILURE);
}

int main() {
    int mapfd;
    struct stat statbuf;
    char *mapbuf;
    int i, count;

    /* a short note on the different return statuses I'm looking for:
       both open() and  stat() are documented as returning -1 on
       failure.  But open() is documented as returning a "small,
       non-negative integer" on success while stat() is documented as
       returning 0  on success.  On the theory that anything other
       than success should be regarded as failure, I'm comparing
       against those success codes.

       Meanwhile, mmap() is documented as returning a pointer, but
       returning MAP_FAILED on failure.  So here I'm looking for
       MAP_FAILED.

       Another brief note is that I'm  opening the file and mapping
       the pages with the least privileges I need to run:  read-only,
       and MAP_SHARED so if any other copy of this program is running
       at the same time we won't block each other.
    */
    if ((mapfd = open(MAPFILE, O_RDONLY)) < 0)
        crash("open");

    if (fstat(mapfd, &statbuf) != 0)
        crash("stat");

    if ((mapbuf = mmap(NULL, statbuf.st_size,
                       PROT_READ, MAP_SHARED, mapfd, 0)) == MAP_FAILED)
        crash("mmap");

    count = 0;
    for (i = 0; i+1 < statbuf.st_size; i++)
        if ((mapbuf[i] == '<') && (mapbuf[i+1] == 'h'))
            count++;

    printf("Number of occurrences:  %d\n", count);
    return(EXIT_SUCCESS);
}

