/* iwm-makedef-win32
 * iwm-makedef-win32.c:
 *
 * Copyright (C) 2006 Kazuki IWAMOTO
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
 
#include <stdio.h>
#include <tchar.h>
#include <windows.h>


int
main (int   argc,
      char *argv[])
{
  int i;
  FILE *fp;
  struct api {
    char *name;
    struct api *prev, *next;
  } *p = NULL;

  for (i = 1; i < argc; i++)
    if (fp = fopen (argv[i], "rb"))
      {
        int j = 0;
        IMAGE_FILE_HEADER ifh;

        if (fread (&ifh, sizeof (IMAGE_FILE_HEADER), 1, fp) == 1)
          while (j < ifh.NumberOfSymbols)
            {
              IMAGE_SYMBOL is;

              if (fseek (fp, ifh.PointerToSymbolTable
                                + j * sizeof (IMAGE_SYMBOL), SEEK_SET) != 0)
                break;
              if (fread (&is, sizeof (IMAGE_SYMBOL), 1, fp) != 1)
                break;
              if (is.SectionNumber > 0 && is.Type == 0x20
                                && is.StorageClass == IMAGE_SYM_CLASS_EXTERNAL)
                {
                  char *name = NULL;

                  if (is.N.Name.Short == 0)
                    {
                      int c, n = 0;

                      if (fseek (fp, ifh.PointerToSymbolTable
                                + ifh.NumberOfSymbols * sizeof (IMAGE_SYMBOL)
                                            + is.N.Name.Long, SEEK_SET) != 0)
                        break;
                      while (c = fgetc (fp), c != EOF && c != '\0')
                        {
                          name = realloc (name, (n + 2) * sizeof (char));
                          name[n++] = c;
                        }
                      if (name)
                        name[n] = '\0';
                    }
                  else
                    {
                      int k;

                      for (k = 0; k < 8; k++)
                        if (is.N.ShortName[k] == '\0')
                          break;
                      if (k > 0)
                        {
                          name = malloc ((k + 1) * sizeof (char));
                          memcpy (name, is.N.ShortName, k * sizeof (char));
                          name[k] = '\0';
                        }
                    }
                  if (name)
                    {
                      if (p)
                        {
                          while (p->next && strcmp (p->name, name) < 0)
                            p = p->next;
                          while (p->prev && strcmp (p->name, name) > 0)
                            p = p->prev;
                          if (strcmp (p->name, name) == 0)
                            {
                              free (name);
                            }
                          else
                            {
                              struct api *q;

                              q = malloc (sizeof (struct api));
                              q->name = name;
                              if (strcmp (p->name, name) > 0)
                                {
                                  q->prev = p->prev;
                                  q->next = p;
                                  p->prev = q;
                                  if (q->prev)
                                    q->prev->next = q;
                                }
                              else
                                {
                                  q->prev = p;
                                  q->next = p->next;
                                  p->next = q;
                                  if (q->next)
                                    q->next->prev = q;
                                }
                            }
                        }
                      else
                        {
                          p = malloc (sizeof (struct api));
                          p->name = name;
                          p->prev = p->next = NULL;
                        }
                    }
                }
              j += is.NumberOfAuxSymbols + 1;
            }
        fclose (fp);
      }
  if (p)
    {
      puts ("EXPORTS");
      while (p->prev)
        p = p->prev;
      while (p)
        {
          if (p->name[0] == '_')
            {
              for (i = 1; p->name[i] != '\0'; i++)
                if (!isalnum (p->name[i]) && p->name[i] != '_')
                  break;
              if (p->name[i] == '\0')
                printf ("\t%s\n", p->name + 1);
            }
          p = p->next;
        }
    }
  return 0;
}
