/* any-to-any.c -- Convert a grok image into another format file. */

/* Copyright (C) 1988, 1990, 1992 Free Software Foundation, Inc.

   This file is part of GNU Finger.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */

#include <stdio.h>
#include "config.h"
#include <sys/types.h>
#include <sys/file.h>
#include <sys/errno.h>
#include <bitmap.h>

#ifndef savestring
#define savestring(s) (char *)strcpy ((char *)xmalloc (1 + strlen (s)), (s))
#endif

extern BITMAP *read_bitmap (), *read_rasterfile (), *read_x_bitmap ();
extern BITMAP *read_lispmug (), *read_grok (), *read_face ();

extern int save_bitmap (), save_rasterfile (), save_x_bitmap ();
extern int save_lispmug ();

typedef int Function ();

struct converter {
  char *name;
  char *doc;
  Function *reader;
  Function *saver;
};

struct converter converters[] = {
  { "rasterfile",
      "A Sun rasterfile file",
      (Function *)read_rasterfile, (Function *)save_rasterfile },

  { "xbitmap",
      "An X11 window system bitmap file",
      (Function *)read_x_bitmap, (Function *)save_x_bitmap },

  { "bitmap",
      "Standard GNU Finger face file",
      (Function *)read_bitmap, (Function *)save_bitmap },

  { "lispmug",
      "An MIT Lispm mugshot",
      (Function *)read_lispmug, (Function *)save_lispmug },

  { "grok",
      "An MIT Grok image (only for reading)",
      (Function *)read_grok, (Function *)NULL },

  { "facesaver",
      "A uunet.uu.net facesaver format file (only for reading)",
      (Function *)read_face, (Function *)NULL },

  { (char *)NULL, (char *)NULL, (Function *)NULL }
};

extern int errno;

char *progname;
Function *output_function = (Function *)save_rasterfile;
Function *input_function = (Function *)read_grok;

main (argc, argv)
     int argc;
     char **argv;
{
  progname = argv[0];

  if (argc == 1)
    usage ("");

  while (--argc)
    {
      char *arg = *++argv;

      /* If input format specified, then choose it. */
      if (strncmp (arg, "-input=", 7) == 0)
	{
	  register int i;

	  arg += 7;

	  for (i = 0; converters[i].name; i++)
	    if (strcmp (arg, converters[i].name) == 0)
	      break;

	  if (converters[i].name)
	    input_function = converters[i].reader;
	  else
	    {
	      fprintf (stderr, "Unknown input format `%s'.\n", arg);
	      usage ();
	    }
	  continue;
	}

      /* If output format specified, then choose it. */
      if (strncmp (arg, "-output=", 8) == 0)
	{
	  register int i;

	  arg += 8;

	  for (i = 0; converters[i].name; i++)
	    if (strcmp (arg, converters[i].name) == 0)
	      break;

	  if (converters[i].name)
	    output_function = converters[i].saver;
	  else
	    {
	      fprintf (stderr, "Unknown output format `%s'.\n", arg);
	      usage ();
	    }
	  continue;
	}

      convert (arg);
    }
}

usage (badarg)
     char *badarg;
{
  register int i;

  fprintf (stderr, "usage: %s -input=TYPE -output=TYPE file ...\n", progname);

  fprintf (stderr,
	   "Input type defaults to GROK, and output type to RASTERFILE.\n");

  for (i = 0; converters[i].name; i++)
    fprintf (stderr, "\t`%s'\t%s.\n", converters[i].name, converters[i].doc);
  exit (1);
}

/* Convert the file named by FILENAME into a mugshot file, and write
   the output to FILENAME.MUG. */
convert (filename)
     char *filename;
{
  char *fname, *newfile, *temp;
  BITMAP *face;

  /* This tricks mugshot_filename () into returning the
     filename unchanged. */
  temp = (char *)rindex (filename, '/');
  if (!temp)
    {
      fname = (char *)xmalloc (3 + strlen (filename));
      sprintf (fname, "./%s", filename);
    }
  else
    fname = savestring (filename);

  newfile = (char *)xmalloc (5 + strlen (fname));
  sprintf (newfile, "%s.mug", fname);

  if (!input_function)
    {
      fprintf (stderr, "The input function specified doesn't exist.\n");
      usage ();
    }

  if (!output_function)
    {
      fprintf (stderr, "The output function specified doesn't exist.\n");
      usage ();
    }

  face = (BITMAP *)(*input_function) (fname);

  if (!face)
    {
      fprintf (stderr, "Can't open input file %s.\n", fname);
      free (fname);
      return;
    }

  (*output_function) (newfile, face);

  free (fname);
  free (newfile);
  free (face->bits);
  free (face);
}


/* **************************************************************** */
/*								    */
/*			How to Read a Grok Image		    */
/*								    */
/* **************************************************************** */

struct grokfile {
  short identifier;		/* Always 1. */
  short depth;
  short width;
  short height;
};

BITMAP *
read_grok (user)
     char *user;
{
  struct grokfile info;
  int file, rowlen;
  byte *buffer;
  BITMAP *face;

  file = mustopen (user, O_RDONLY, 0666);

  /* Get the header of the file. */
  read (file, &info, sizeof (info));

  BYTESWAP (info.identifier);
  BYTESWAP (info.width);
  BYTESWAP (info.height);
  BYTESWAP (info.depth);

  if (info.identifier != 1 ||
      (info.depth != 1 && info.depth != 8))
    {
      close (file);
      fprintf (stderr, "%s is not a grok format file.\n");
      return;
    }

  if (info.depth == 8)
    rowlen = info.width;
  else
    rowlen = ROWBYTES (info.width);

  /* Get the rest of the bits. */
  buffer = (byte *)xmalloc (info.height * rowlen);
  read (file, buffer, info.height * rowlen);
  close (file);

  if (info.depth == 8)
    {
      byte *newbits, *dither ();

      newbits = dither (buffer, info.width, info.height, rowlen);
      free (buffer);
      buffer = newbits;
      rowlen = ROWBYTES (info.width);
    }

  face = (BITMAP *)xmalloc (sizeof (BITMAP));

  face->width = info.width;
  face->height = info.height;
  face->rowlen = rowlen;
  face->bits = buffer;
  return (face);
}

/* Open FILENAME in MODE with FLAGS.  Return the file descriptor of the
   newly opened file if successful, or print file system error, and exit
   the program if not. */
int
mustopen (filename, mode, flags)
     char *filename;
     int mode, flags;
{
  int result = open (filename, mode, flags);

  if (result == -1)
    {
      result = errno;
      perror (filename);
      exit (result);
    }

  return (result);
}
