/*
    iwm-makedef-win32
    Copyright (C) 2006 Kazuki IWAMOTO

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 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
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  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;
}
