/*****************************************************************
 * flpbm.c: FBM Release 1.0 25-Feb-90 Michael Mauldin
 *
 * Copyright (C) 1989,1990 by Michael Mauldin.  Permission is granted
 * to use this file in whole or in part for any purpose, educational,
 * recreational or commercial, provided that this copyright notice
 * is retained unchanged.  This software is available to all free of
 * charge by anonymous FTP and in the UUNET archives.
 *
 * flpbm.c: 
 *
 * CONTENTS
 *	read_pbm (image, infile, mstr, mlen)
 *	write_pbm (image, stream)
 *
 * EDITLOG
 *	LastEditDate = Mon Jun 25 00:17:08 1990 - Michael Mauldin
 *	LastFileName = /usr2/mlm/src/misc/fbm/flpbm.c
 *
 * HISTORY
 * 25-Jun-90  Michael Mauldin (mlm@cs.cmu.edu) Carnegie Mellon
 *	Package for Release 1.0
 *
 * 07-Mar-89  Michael Mauldin (mlm) at Carnegie Mellon University
 *	Beta release (version 0.9) mlm@cs.cmu.edu
 *
 * 12-Nov-88  Michael Mauldin (mlm) at Carnegie-Mellon University
 *	Created.
 *****************************************************************/

# include <stdio.h>
# include <math.h>
# include <ctype.h>
# include "fbm.h"

/****************************************************************
 * read_pbm: Read a pbm file into an fbm bitmap
 ****************************************************************/

#ifndef lint
static char *fbmid =
"$FBM flpbm.c <1.0> 25-Jun-90  (C) 1989,1990 by Michael Mauldin, source \
code available free from MLM@CS.CMU.EDU and from UUNET archives$";
#endif

read_pbm (image, infile, mstr, mlen)
FBM *image;
FILE *infile;
char *mstr;
int mlen;
{ register int ch, i, j;
  register unsigned char *bmp;
  char cmtbuf[128], *s;

  if ((ch = NEXTMCH (infile, mstr, mlen)) != 'P' || 
      (ch = NEXTMCH (infile, mstr, mlen)) != '1')
  { fprintf (stderr, "bad magic number, input not PBM file\n");
    return (0);
  }

  image->hdr.cols = pbm_getint (infile);
  image->hdr.rows = pbm_getint (infile);
  image->hdr.planes = 1;
  image->hdr.bits = 1;  
  image->hdr.physbits = 8;
  image->hdr.rowlen = 16 * ((image->hdr.cols + 15) / 16);
  image->hdr.plnlen = image->hdr.rowlen * image->hdr.rows;
  image->hdr.clrlen = 0;
  image->hdr.aspect = 1.0;
  image->hdr.title[0] = '\0';
  
  if (image->hdr.cols < 1 || image->hdr.rows < 1)
  { fprintf (stderr, "Error, specified size %d by %d\n",
	     image->hdr.cols, image->hdr.rows);
    return (0);
  }
  
  fprintf (stderr,
	   "Reading PBM file \"%s\" [%dx%dx1]\n",
	   image->hdr.title[0] ? image->hdr.title : "",
	   image->hdr.cols, image->hdr.rows);

  alloc_fbm (image);

  for (j=0; j<image->hdr.rows; j++)
  { bmp = &(image->bm[j * image->hdr.rowlen]);

    for (i=0; i<image->hdr.cols; i++)
    { while ((ch = fgetc (infile)) != EOF)
      { if (ch == '0') { *bmp++ = WHITE; break; }

        else if (ch == '1') { *bmp++ = BLACK; break; }

	else if (ch == '#')
        { s = cmtbuf; *s++ = '#';
	  while ((ch = fgetc (infile)) != EOF && ch != '\n') *s++ = ch;
	  *s = '\0';
	  for (s=cmtbuf; *s == '#' || isspace (*s); s++) ;
	  if (!strncmp (s, "Title: ", 7)) strcpy (image->hdr.title, s+7);
	  fprintf (stderr, "Read_pbm found title '%s'\n",
		   image->hdr.title);
	}
      }
      
      if (ch == EOF)
      { fprintf (stderr, "premature EOF, row %d, col %d\n", j, i);
        return (0);
      }
    }
  }

  
  return (1);
}

/****************************************************************
 * pbm_getint: Read a number from a PBM file, ignoring comments
 ****************************************************************/

# define START 1
# define COMMENT 2
# define INTEGER 3

pbm_getint (infile)
FILE *infile;
{ char buf[80];
  register char *s = buf;
  register int ch;
  int state = START;

  while (1)
  { if ((ch = fgetc (infile)) == EOF)
    { fprintf (stderr, "premature EOF\n");
      return (0);
    }

    switch (state)
    { case START:	if (isspace (ch)) ;
			else if (ch == '#') state = COMMENT;
			else if (isdigit (ch))
			{ *s++ = ch; state = INTEGER; }
			else
			{ fprintf (stderr, "bad INTEGER in input");
			  return (0);
			}
			break;

      case COMMENT:	if (ch == '\n') state = START;
			break;

      case INTEGER:	if (isdigit (ch)) *s++ = ch;
			else
			{ register int result;

			  *s = '\0';
			  result = atoi (buf);
			  return (result);
			}
			break;

      default:		fprintf (stderr, "impossible state %d\n", state);
			return (0);
    }
  }
}

/****************************************************************
 * write_pbm: Write a bitmap in PBM format to the output device
 ****************************************************************/

write_pbm (image, stream)
register FBM *image;
FILE *stream;
{ register int i, j, outcol = 0;
  register unsigned char *bmp;

  /* Write PBM header lines */
  fprintf (stream, "P1\n%d %d\n", image->hdr.cols, image->hdr.rows);
  if (image->hdr.title[0])
  { fprintf (stream, "# Title: %s\n", image->hdr.title); }
  
  /* Now write out 1s and 0s, in 70 character lines */
  for (j=0; j < image->hdr.rows; j++)
  { bmp = &(image->bm[j * image->hdr.rowlen]);

    for (i=0; i < image->hdr.cols; i++)
    { fputc (*bmp++ ? '0' : '1', stream);	/* In PBM 1=black, not white */
      if (++outcol >= 70) { fprintf (stream, "\n"); outcol=0; }
    }
    if (outcol) { fprintf (stream, "\n"); outcol=0; }
  }
  
  return (1);
}
