(root)/
gcc-13.2.0/
gcc/
m2/
tools-src/
mklink.c
       1  /* mklink.c creates startup code and the link command line.
       2  
       3  Copyright (C) 2000-2023 Free Software Foundation, Inc.
       4  Contributed by Gaius Mulley <gaius@glam.ac.uk>.
       5  
       6  This file is part of GNU Modula-2.
       7  
       8  GNU Modula-2 is free software; you can redistribute it and/or modify
       9  it under the terms of the GNU General Public License as published by
      10  the Free Software Foundation; either version 3, or (at your option)
      11  any later version.
      12  
      13  GNU Modula-2 is distributed in the hope that it will be useful, but
      14  WITHOUT ANY WARRANTY; without even the implied warranty of
      15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16  General Public License for more details.
      17  
      18  You should have received a copy of the GNU General Public License
      19  along with GNU Modula-2; see the file COPYING3.  If not see
      20  <http://www.gnu.org/licenses/>.  */
      21  
      22  
      23  #include "config.h"
      24  #include "system.h"
      25  
      26  #define MAX_FILE_NAME 8192
      27  #define MAXSTACK 4096
      28  #define STDIN 0
      29  #define STDOUT 1
      30  #define ENDOFILE ((char)-1)
      31  #define ERROR(X) \
      32    (fprintf (stderr, "%s:%d error %s\n", __FILE__, __LINE__, X) \
      33     && (fflush (stderr)))
      34  #define DEBUG(X) \
      35    ((Debug) && (fprintf (stderr, "%s\n", X) && (fflush (stderr))))
      36  
      37  #if !defined(TRUE)
      38  #define TRUE (1 == 1)
      39  #endif
      40  
      41  #if !defined(FALSE)
      42  #define FALSE (1 == 0)
      43  #endif
      44  
      45  typedef struct functlist
      46  {
      47    char *functname;
      48    struct functlist *next;
      49  } functList;
      50  
      51  /* Prototypes.  */
      52  
      53  static void ParseFileLinkCommand (void);
      54  static void ParseFileStartup (void);
      55  static void ParseFile (char *Name);
      56  static void ParseComments (void);
      57  static void CopyUntilEof (void);
      58  static void CopyUntilEol (void);
      59  static int IsSym (char *s);
      60  static int SymIs (char *s);
      61  static int FindString (char *String);
      62  static void GetNL (void);
      63  static char GetChar (void);
      64  static void ResetBuffer (void);
      65  static int GetSingleChar (char *ch);
      66  static int InRange (int Element, unsigned int Min, unsigned int Max);
      67  static char PutChar (char ch);
      68  static int IsSpace (char ch);
      69  static void SkipSpaces (void);
      70  static void SkipText (void);
      71  static void SilentSkipSpaces (void);
      72  static void SilentSkipText (void);
      73  static void PushBack (char *s);
      74  static int IsDigit (char ch);
      75  static void GetName (char *Name);
      76  static void OpenOutputFile (void);
      77  static void CloseFile (void);
      78  static void FindSource (char *Name);
      79  static void CopyUntilEolInto (char *Buffer);
      80  static void FindObject (char *Name);
      81  static int IsExists (char *Name);
      82  
      83  /* Global variables.  */
      84  
      85  static char *NameOfFile = NULL;
      86  static const char *NameOfMain = "main";
      87  static int StackPtr = 0;
      88  static char Stack[MAXSTACK];
      89  static int CurrentFile = STDIN;
      90  static int OutputFile;
      91  static int LinkCommandLine = FALSE;
      92  static int ProfilePCommand = FALSE;
      93  static int ProfilePGCommand = FALSE;
      94  static int ExitNeeded = TRUE;
      95  static char *libraries = NULL;
      96  static char *args = NULL;
      97  static functList *head = NULL;
      98  static functList *tail = NULL;
      99  static int langC = FALSE; /* FALSE = C++, TRUE = C.  */
     100  
     101  /* addLibrary - adds libname to the list of libraries to be linked.  */
     102  
     103  static void
     104  addLibrary (char *libname)
     105  {
     106    if (libraries == NULL)
     107      libraries = strdup (libname);
     108    else
     109      {
     110        char *old = libraries;
     111        char *newlib
     112            = (char *)malloc (strlen (libname) + strlen (libraries) + 1 + 1);
     113        strcpy (newlib, libraries);
     114        strcat (newlib, " ");
     115        strcat (newlib, libname);
     116        libraries = newlib;
     117        free (old);
     118      }
     119  }
     120  
     121  /* addGccArg - adds arg to the list of gcc arguments.  */
     122  
     123  static void
     124  addGccArg (char *arg)
     125  {
     126    if (args == NULL)
     127      args = strdup (arg);
     128    else
     129      {
     130        char *old = args;
     131        char *newarg = (char *)malloc (strlen (old) + strlen (arg) + 1 + 1);
     132        strcpy (newarg, old);
     133        strcat (newarg, " ");
     134        strcat (newarg, arg);
     135        args = newarg;
     136        free (old);
     137      }
     138  }
     139  
     140  int
     141  main (int argc, char *argv[])
     142  {
     143    int i;
     144  
     145    if (argc >= 3)
     146      {
     147        if (strcmp (argv[1], "-l") == 0)
     148  	LinkCommandLine = TRUE;
     149        else if (strcmp (argv[1], "-s") == 0)
     150  	LinkCommandLine = FALSE;
     151        else
     152          {
     153            fprintf (stderr, "Usage: mklink (-l|-s) [--langc|--langc++] [--pg|-p] "
     154                             "[--lib library] [--main name] [--exit] --name "
     155                             "filename <modulelistfile>\n");
     156            fprintf (stderr, "       must supply -l or -s option\n");
     157            exit (1);
     158          }
     159        ProfilePCommand = FALSE;
     160        ProfilePGCommand = FALSE;
     161        i = 2;
     162        while (i < argc - 1)
     163          {
     164            if (strcmp (argv[i], "--langc++") == 0)
     165  	    langC = FALSE;
     166            else if (strcmp (argv[i], "--langc") == 0)
     167  	    langC = TRUE;
     168            else if (strncmp (argv[i], "-f", 2) == 0)
     169  	    addGccArg (argv[i]);
     170            else if (strcmp (argv[i], "--pg") == 0)
     171  	    ProfilePGCommand = TRUE;
     172            else if (strcmp (argv[i], "-p") == 0)
     173  	    ProfilePCommand = TRUE;
     174            else if (strcmp (argv[i], "--exit") == 0)
     175  	    ExitNeeded = FALSE;
     176            else if (strcmp (argv[i], "--lib") == 0)
     177              {
     178                i++;
     179                addLibrary (argv[i]);
     180              }
     181            else if (strcmp (argv[i], "--main") == 0)
     182              {
     183                i++;
     184                NameOfMain = argv[i];
     185              }
     186            else if (strcmp (argv[i], "--name") == 0)
     187              {
     188                i++;
     189                NameOfFile = argv[i];
     190              }
     191            i++;
     192          }
     193        ParseFile (argv[i]);
     194      }
     195    else
     196      {
     197        fprintf (stderr, "Usage: mklink (-l|-s) [--gcc|--g++] [--pg|-p] [--lib "
     198                         "library] [--main name] [--exit] --name filename "
     199                         "<modulelistfile>\n");
     200        exit (1);
     201      }
     202    if (NameOfFile == NULL)
     203      {
     204        fprintf (stderr, "mklink must have a --name argument\n");
     205        fprintf (stderr, "Usage: mklink (-l|-s) [--gcc|--g++] [--pg|-p] [--lib "
     206                         "library] [--main name] [--exit] --name filename "
     207                         "<modulelistfile>\n");
     208        exit (1);
     209      }
     210    exit (0);
     211  }
     212  
     213  /* ParseFile - parses the input file and generates the output file.  */
     214  
     215  static void
     216  ParseFile (char *Name)
     217  {
     218    FindSource (Name);
     219    OpenOutputFile ();
     220    if (LinkCommandLine)
     221      ParseFileLinkCommand ();
     222    else
     223      ParseFileStartup ();
     224    CloseFile ();
     225  }
     226  
     227  /* ParseFileLinkCommand - generates the link command.  */
     228  
     229  static void
     230  ParseFileLinkCommand (void)
     231  {
     232    char name[MAX_FILE_NAME];
     233    char *s = NULL;
     234    char *l = NULL;
     235    char *c = NULL;
     236  
     237    s = getenv ("CC");
     238    if (s == NULL)
     239      {
     240        if (langC)
     241          printf ("gcc -g ");
     242        else
     243          printf ("g++ -g ");
     244      }
     245    else
     246      printf ("%s -g ", s);
     247  
     248    if (args != NULL)
     249      printf ("%s ", args);
     250  
     251    l = getenv ("LDFLAGS");
     252    if (l != NULL)
     253      printf ("%s ", l);
     254  
     255    c = getenv ("CFLAGS");
     256    if (c != NULL)
     257      printf ("%s ", c);
     258  
     259    if (ProfilePGCommand)
     260      printf (" -pg");
     261    else if (ProfilePCommand)
     262      printf (" -p");
     263  
     264    while (PutChar (GetChar ()) != (char)EOF)
     265      {
     266        CopyUntilEolInto (name);
     267        if ((strlen (name) > 0) && (name[0] != '#'))
     268          FindObject (name);
     269      }
     270    printf (" %s\n", libraries);
     271  }
     272  
     273  /* FindObject - searches the M2PATH variable to find the object file.
     274     If it finds the object file it prints it to stdout otherwise it
     275     writes an error on stderr.  */
     276  
     277  static void
     278  FindObject (char *Name)
     279  {
     280    char m2search[4096];
     281    char m2path[4096];
     282    char name[4096];
     283    char exist[4096];
     284    int s, p;
     285  
     286    if (getenv ("M2PATH") == NULL)
     287      strcpy (m2path, ".");
     288    else
     289      strcpy (m2path, getenv ("M2PATH"));
     290  
     291    snprintf (name, sizeof (name), "%s.o", Name);
     292    p = 0;
     293    while (m2path[p] != (char)0)
     294      {
     295        s = 0;
     296        while ((m2path[p] != (char)0) && (m2path[p] != ' '))
     297          {
     298            m2search[s] = m2path[p];
     299            s++;
     300            p++;
     301          }
     302        if (m2path[p] == ' ')
     303  	p++;
     304        m2search[s] = (char)0;
     305        snprintf (exist, sizeof (exist), "%s/%s", m2search, name);
     306        if (IsExists (exist))
     307          {
     308            printf (" %s", exist);
     309            return;
     310          }
     311      }
     312    fprintf (stderr, "cannot find %s\n", name);
     313  }
     314  
     315  /* IsExists - returns true if a file, Name, exists.  It returns false
     316     otherwise.  */
     317  
     318  static int
     319  IsExists (char *Name)
     320  {
     321    struct stat buf;
     322  
     323    return (stat (Name, &buf) == 0);
     324  }
     325  
     326  /* add_function - adds a name to the list of functions, in order.  */
     327  
     328  void
     329  add_function (char *name)
     330  {
     331    functList *p = (functList *)malloc (sizeof (functList));
     332    p->functname = (char *)malloc (strlen (name) + 1);
     333    strcpy (p->functname, name);
     334  
     335    if (head == NULL)
     336      {
     337        head = p;
     338        tail = p;
     339        p->next = NULL;
     340      }
     341    else
     342      {
     343        tail->next = p;
     344        tail = p;
     345        tail->next = NULL;
     346      }
     347  }
     348  
     349  static void
     350  GenerateInitCalls (functList *p)
     351  {
     352    while (p != NULL)
     353      {
     354        printf ("   _M2_%s_init (argc, argv, envp);\n", p->functname);
     355        p = p->next;
     356      }
     357  }
     358  
     359  static void
     360  GenerateFinishCalls (functList *p)
     361  {
     362    if (p->next != NULL)
     363      GenerateFinishCalls (p->next);
     364    printf ("   _M2_%s_fini (argc, argv, envp);\n", p->functname);
     365  }
     366  
     367  static void
     368  GeneratePrototypes (functList *p)
     369  {
     370    while (p != NULL)
     371      {
     372        if (langC)
     373          {
     374            printf ("extern void _M2_%s_init (int argc, char *argv[], char *envp[]);\n",
     375                    p->functname);
     376            printf ("extern void _M2_%s_fini (int argc, char *argv[], char *envp[]);\n",
     377                    p->functname);
     378          }
     379        else
     380          {
     381            printf ("extern \"C\" void _M2_%s_init (int argc, char *argv[], char *envp[]);\n",
     382                    p->functname);
     383            printf ("extern \"C\" void _M2_%s_fini (int argc, char *argv[], char *envp[]);\n",
     384                    p->functname);
     385          }
     386        p = p->next;
     387      }
     388  }
     389  
     390  /* ParseFileStartup - generates the startup code.  */
     391  
     392  static void
     393  ParseFileStartup (void)
     394  {
     395    char name[MAX_FILE_NAME];
     396    functList *p;
     397  
     398    while (PutChar (GetChar ()) != (char)EOF)
     399      {
     400        CopyUntilEolInto (name);
     401        if ((strlen (name) > 0) && (strcmp (name, "mod_init") != 0)
     402            && (name[0] != '#'))
     403  	add_function (name);
     404      }
     405    GeneratePrototypes (head);
     406    printf ("extern");
     407    if (!langC)
     408      printf (" \"C\"");
     409    printf (" void _exit(int);\n");
     410  
     411    printf ("\n\nint %s(int argc, char *argv[], char *envp[])\n", NameOfMain);
     412    printf ("{\n");
     413    GenerateInitCalls (head);
     414    GenerateFinishCalls (head);
     415    if (ExitNeeded)
     416      printf ("   _exit(0);\n");
     417    printf ("   return(0);\n");
     418    printf ("}\n");
     419  }
     420  
     421  /* OpenOutputFile - shut down stdout and open the new mod_init.c */
     422  
     423  static void
     424  OpenOutputFile (void)
     425  {
     426    if (strcmp (NameOfFile, "-") != 0)
     427      {
     428        if (close (STDOUT) != 0)
     429          {
     430            ERROR ("Unable to close stdout");
     431            exit (1);
     432          }
     433        OutputFile = creat (NameOfFile, 0666);
     434        if (OutputFile != STDOUT)
     435          {
     436            ERROR ("Expected that the file descriptor should be 1");
     437          }
     438      }
     439  }
     440  
     441  /* CloseFile - flush and close the file.  */
     442  
     443  static void
     444  CloseFile (void)
     445  {
     446  #if 0
     447    fflush(stdout);
     448    if (close(STDOUT) != 0) {
     449      ERROR("Unable to close our output file"); exit(1);
     450    }
     451  #endif
     452  }
     453  
     454  /* CopyUntilEof - copies from the current input marker until ENDOFILE
     455     is reached.  */
     456  
     457  static void
     458  CopyUntilEof (void)
     459  {
     460    char ch;
     461  
     462    while ((ch = GetChar ()) != ENDOFILE)
     463      putchar (ch);
     464  }
     465  
     466  /* CopyUntilEol - copies from the current input marker until '\n' is
     467     reached.  */
     468  
     469  static void
     470  CopyUntilEol (void)
     471  {
     472    char ch;
     473  
     474    while (((ch = GetChar ()) != '\n') && (ch != (char)EOF))
     475      putchar (ch);
     476    if (ch == '\n')
     477      putchar (ch);
     478  }
     479  
     480  /* CopyUntilEolInto - copies from the current input marker until '\n'
     481     is reached into a Buffer.  */
     482  
     483  static void
     484  CopyUntilEolInto (char *Buffer)
     485  {
     486    char ch;
     487    int i = 0;
     488  
     489    while (((ch = GetChar ()) != '\n') && (ch != (char)EOF))
     490      {
     491        Buffer[i] = ch;
     492        i++;
     493      }
     494    if ((ch == '\n') || (ch == (char)EOF))
     495      Buffer[i] = (char)0;
     496  }
     497  
     498  /* IsSym - returns true if string, s, was found in the input stream.
     499     The input stream is uneffected.  */
     500  
     501  static int
     502  IsSym (char *s)
     503  {
     504    int i = 0;
     505  
     506    while ((s[i] != (char)0) && (s[i] == PutChar (GetChar ())))
     507      {
     508        GetChar ();
     509        i++;
     510      }
     511    if (s[i] == (char)0)
     512      {
     513        PushBack (s);
     514        /* found s in input string.  */
     515        return (TRUE);
     516      }
     517    else
     518      {
     519        /* push back the characters we have scanned.  */
     520        if (i > 0)
     521          {
     522            do
     523              {
     524                i--;
     525                PutChar (s[i]);
     526              }
     527            while (i > 0);
     528          }
     529        return (FALSE);
     530      }
     531  }
     532  
     533  /* SymIs - returns true if string, s, was found in the input stream.
     534     The token s is consumed from the input stream.  */
     535  
     536  static int
     537  SymIs (char *s)
     538  {
     539    int i = 0;
     540  
     541    while ((s[i] != (char)0) && (s[i] == PutChar (GetChar ())))
     542      {
     543        GetChar ();
     544        i++;
     545      }
     546    if (s[i] == (char)0)
     547      {
     548        /* found s in input string.  */
     549        return (TRUE);
     550      }
     551    else
     552      {
     553        /* push back the characters we have scanned.  */
     554        if (i > 0)
     555          {
     556            do
     557              {
     558                i--;
     559                PutChar (s[i]);
     560              }
     561            while (i > 0);
     562          }
     563        return (FALSE);
     564      }
     565  }
     566  
     567  /* FindString - keeps on reading input until a string, String, is
     568     matched.  If end of file is reached then FALSE is returned, otherwise
     569     TRUE is returned.  */
     570  
     571  static int
     572  FindString (char *String)
     573  {
     574    int StringIndex = 0;
     575    int Found = FALSE;
     576    int eof = FALSE;
     577    char ch;
     578  
     579    while ((!Found) && (!eof))
     580      {
     581        if (String[StringIndex] == (char)0)
     582  	/* must have found string.  */
     583  	Found = TRUE;
     584        else
     585          {
     586            ch = GetChar ();
     587            eof = (ch == ENDOFILE);
     588            if (ch == String[StringIndex])
     589  	    StringIndex++;
     590            else
     591  	    StringIndex = 0;
     592          }
     593      }
     594    return (Found);
     595  }
     596  
     597  /* GetNL - keeps on reading input from until a new line is found.  */
     598  
     599  static void
     600  GetNL (void)
     601  {
     602    char ch;
     603  
     604    while ((ch = GetChar ()) != '\n')
     605      putchar (ch);
     606    putchar ('\n');
     607  }
     608  
     609  /* GetChar - returns the current character in input.  */
     610  
     611  static char
     612  GetChar (void)
     613  {
     614    char ch;
     615  
     616    if (StackPtr > 0)
     617      {
     618        StackPtr--;
     619        return (Stack[StackPtr]);
     620      }
     621    else
     622      {
     623        if (GetSingleChar (&ch))
     624  	return (ch);
     625        else
     626  	return (ENDOFILE);
     627      }
     628  }
     629  
     630  #define MAXBUF 0x1000
     631  static int Pointer = 0;
     632  static int AmountRead = 0;
     633  static char Buffer[MAXBUF];
     634  
     635  /* ResetBuffer - resets the buffer information to an initial state.  */
     636  
     637  static void
     638  ResetBuffer (void)
     639  {
     640    StackPtr = 0;
     641    Pointer = 0;
     642    AmountRead = 0;
     643  }
     644  
     645  /* GetSingleChar - gets a single character from input.  TRUE is
     646     returned upon success.  */
     647  
     648  static int
     649  GetSingleChar (char *ch)
     650  {
     651    if (Pointer == AmountRead)
     652      {
     653        AmountRead = read (CurrentFile, &Buffer, MAXBUF);
     654        if (AmountRead < 0)
     655  	AmountRead = 0;
     656        Pointer = 0;
     657      }
     658    if (Pointer == AmountRead)
     659      {
     660        *ch = ENDOFILE;
     661        return (FALSE);
     662      }
     663    else
     664      {
     665        *ch = Buffer[Pointer];
     666        Pointer++;
     667        return (TRUE);
     668      }
     669  }
     670  
     671  /* InRange - returns true if Element is within the range Min..Max.  */
     672  
     673  static int
     674  InRange (int Element, unsigned int Min, unsigned int Max)
     675  {
     676    return ((Element >= Min) && (Element <= Max));
     677  }
     678  
     679  /* PutChar - pushes a character back onto input.  This character is
     680     also returned.  */
     681  
     682  static char
     683  PutChar (char ch)
     684  {
     685    if (StackPtr < MAXSTACK)
     686      {
     687        Stack[StackPtr] = ch;
     688        StackPtr++;
     689      }
     690    else
     691      {
     692        ERROR ("Stack overflow in PutChar");
     693      }
     694    return (ch);
     695  }
     696  
     697  /* IsSpace - returns true if character, ch, is a space.  */
     698  
     699  static int
     700  IsSpace (char ch)
     701  {
     702    return ((ch == ' ') || (ch == '\t'));
     703  }
     704  
     705  /* SkipSpaces - eats up spaces in input.  */
     706  
     707  static void
     708  SkipSpaces (void)
     709  {
     710    while (IsSpace (PutChar (GetChar ())))
     711      putchar (GetChar ());
     712  }
     713  
     714  /* SilentSkipSpaces - eats up spaces in input.  */
     715  
     716  static void
     717  SilentSkipSpaces (void)
     718  {
     719    char ch;
     720  
     721    while (IsSpace (PutChar (GetChar ())))
     722      ch = GetChar (); /* throw away character.  */
     723  }
     724  
     725  /* SkipText - skips ascii text, it does not skip white spaces.  */
     726  
     727  static void
     728  SkipText (void)
     729  {
     730    while (!IsSpace (PutChar (GetChar ())))
     731      putchar (GetChar ());
     732  }
     733  
     734  /* SilentSkipText - skips ascii text, it does not skip white spaces.  */
     735  
     736  static void
     737  SilentSkipText (void)
     738  {
     739    char ch;
     740  
     741    while (!IsSpace (PutChar (GetChar ())))
     742      ch = GetChar (); /* throw away character.  */
     743  }
     744  
     745  /* PushBack - pushes a string, backwards onto the input stack.  */
     746  
     747  static void
     748  PushBack (char *s)
     749  {
     750    int i;
     751  
     752    i = strlen (s);
     753    while (i > 0)
     754      {
     755        i--;
     756        PutChar (s[i]);
     757      }
     758  }
     759  
     760  /* IsDigit - returns true if a character, ch, is a decimal digit.  */
     761  
     762  static int
     763  IsDigit (char ch)
     764  {
     765    return (((ch >= '0') && (ch <= '9')));
     766  }
     767  
     768  /* GetName - returns the next name found.  */
     769  
     770  static void
     771  GetName (char *Name)
     772  {
     773    int i;
     774    char ch;
     775  
     776    SkipSpaces ();
     777    ch = GetChar ();
     778    i = 0;
     779    while (!IsSpace (ch))
     780      {
     781        Name[i] = ch;
     782        i++;
     783        ch = GetChar ();
     784      }
     785    Name[i] = '\0';
     786  }
     787  
     788  /* FindSource - open source file on StdIn.  */
     789  
     790  static void
     791  FindSource (char *Name)
     792  {
     793    if (close (STDIN) != 0)
     794      {
     795        ERROR ("close on STDIN failed");
     796      }
     797    CurrentFile = open (Name, O_RDONLY);
     798    if (CurrentFile < 0)
     799      {
     800        perror ("failed to open file");
     801        exit (1);
     802      }
     803    if (CurrentFile != STDIN)
     804      {
     805        ERROR ("Expecting file descriptor value of 1");
     806      }
     807  }