public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
From: Kai Tietz <Kai.Tietz@onevision.com>
To: Christopher Faylor <cgf-use-the-mailinglist-please@sourceware.org>
Cc: binutils@sourceware.org
Subject: Re: PATCH: windres
Date: Mon, 23 Apr 2007 13:51:00 -0000	[thread overview]
Message-ID: <OF87B638C3.6DB54863-ONC12572C6.004648B2-C12572C6.00470D13@onevision.de> (raw)
In-Reply-To: <20070423122553.GA1513@ednor.casa.cgf.cx>

[-- Attachment #1: Type: text/plain, Size: 1294 bytes --]

binutils-owner@sourceware.org wrote on 23.04.2007 14:25:54:

> I'm sorry that I missed this before but what was the rationale for
> replacing the (f)lex file with a .c file?  That seems like a step 
backwards
> to me.

The use of flex looks more professional, but at a closer look a pure c 
lexer is getting
easier to maintain and more efficant. E.g. gcc use now for a long term no 
flex anymore to
implement the c token scanner. To use flex is sometimes as to break a fly 
on the wheel.
 
> You also have \r\n endings in the file that you provided.  It's a minor
> issue but, as long as I'm here...

Upps. Corrected it, see attachment ;)

Regards,
 i.A. Kai Tietz



------------------------------------------------------------------------------------------
  OneVision Software Entwicklungs GmbH & Co. KG
  Dr.-Leo-Ritter-Straße 9 - 93049 Regensburg
  Tel: +49.(0)941.78004.0 - Fax: +49.(0)941.78004.489 - www.OneVision.com
  Commerzbank Regensburg - BLZ 750 400 62 - Konto 6011050
  Handelsregister: HRA 6744, Amtsgericht Regensburg
  Komplementärin: OneVision Software Entwicklungs Verwaltungs GmbH
  Dr.-Leo-Ritter-Straße 9 – 93049 Regensburg
  Handelsregister: HRB 8932, Amtsgericht Regensburg - Geschäftsführer: 
Ulrike Döhler, Manuela Kluger


[-- Attachment #2: rclex.c --]
[-- Type: application/octet-stream, Size: 15935 bytes --]

/* rclex.c -- lexer for Windows rc files parser  */

/* Copyright 1997, 1998, 1999, 2001, 2002, 2003, 2005, 2006
   Free Software Foundation, Inc.
   Written by Ian Lance Taylor, Cygnus Support.

   This file is part of GNU Binutils.

   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 of the License, 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., 51 Franklin Street - Fifth Floor, Boston, MA
   02110-1301, USA.  */

/* This is a lexer used by the Windows rc file parser.  It basically
   just recognized a bunch of keywords.  */

#include "bfd.h"
#include "bucomm.h"
#include "libiberty.h"
#include "safe-ctype.h"
#include "windres.h"
#include "rcparse.h"

#include <assert.h>

/* Lexer input stream.  */
FILE *yyin = NULL;

/* Whether we are in rcdata mode, in which we returns the lengths of
   strings.  */

static int rcdata_mode;

/* Whether we are supressing lines from cpp (including windows.h or
   headers from your C sources may bring in externs and typedefs).
   When active, we return IGNORED_TOKEN, which lets us ignore these
   outside of resource constructs.  Thus, it isn't required to protect
   all the non-preprocessor lines in your header files with #ifdef
   RC_INVOKED.  It also means your RC file can't include other RC
   files if they're named "*.h".  Sorry.  Name them *.rch or whatever.  */

static int suppress_cpp_data;

#define MAYBE_IGNORE(x) (suppress_cpp_data ? IGNORED_TOKEN : (x))

/* The first filename we detect in the cpp output.  We use this to
   tell included files from the original file.  */

static char *initial_fn;

/* List of allocated strings.  */

struct alloc_string
{
  struct alloc_string *next;
  char *s;
};

static struct alloc_string *strings;

/* List of keywords detected by the lexer.  */
struct rclex_keywords
{
  const char *name;
  int tok;
};

static int rclex_translatekeyword (const char *);

static const struct rclex_keywords keywds[] =
{
  { "ACCELERATORS", ACCELERATORS },
  { "ALT", ALT },
#if 0
  { "ANICURSOR", ANICURSOR }, /* RT_ANICURSOR (21) */
  { "ANIICON", ANIICON }, /* RT_ANIICON (22) */
#endif
  { "ASCII", ASCII },
  { "AUTO3STATE", AUTO3STATE },
  { "AUTOCHECKBOX", AUTOCHECKBOX },
  { "AUTORADIOBUTTON", AUTORADIOBUTTON },
  { "BEDIT", BEDIT },
  { "BEGIN", BEG },
  { "BITMAP", BITMAP },
  { "BLOCK", BLOCK },
#if 0
  { "BUTTON", BUTTON },
#endif
  { "CAPTION", CAPTION },
  { "CHARACTERISTICS", CHARACTERISTICS },
  { "CHECKBOX", CHECKBOX },
  { "CHECKED", CHECKED },
  { "CLASS", CLASS },
  { "COMBOBOX", COMBOBOX },
  { "CONTROL", CONTROL },
  { "CTEXT", CTEXT },
  { "CURSOR", CURSOR },
  { "DEFPUSHBUTTON", DEFPUSHBUTTON },
  { "DIALOG", DIALOG },
  { "DIALOGEX", DIALOGEX },
  { "DISCARDABLE", DISCARDABLE },
#if 0
  { "DLGINCLUDE", DLGINCLUDE },
  { "DLGINIT", DLGINIT },
#endif
  { "EDITTEXT", EDITTEXT },
  { "END", END },
  { "EXSTYLE", EXSTYLE },
  { "FILEFLAGS", FILEFLAGS },
  { "FILEFLAGSMASK", FILEFLAGSMASK },
  { "FILEOS", FILEOS },
  { "FILESUBTYPE", FILESUBTYPE },
  { "FILETYPE", FILETYPE },
  { "FILEVERSION", FILEVERSION },
  { "FIXED", FIXED },
  { "FONT", FONT },
#if 0
  { "FONTDIR", FONTDIR },
#endif
  { "GRAYED", GRAYED },
  { "GROUP_CURSOR", RT_GROUP_CURSOR},
  { "GROUP_ICON", RT_GROUP_ICON },
  { "GROUPBOX", GROUPBOX },
  { "HEDIT", HEDIT },
  { "HELP", HELP },
#if 0
  { "HTML", HTML }, /* RT_HTML (23) */
#endif
  { "ICON", ICON },
  { "IEDIT", IEDIT },
  { "IMPURE", IMPURE },
  { "INACTIVE", INACTIVE },
  { "LANGUAGE", LANGUAGE },
  { "LISTBOX", LISTBOX },
  { "LOADONCALL", LOADONCALL },
  { "LTEXT", LTEXT },
#if 0
  { "MANIFEST", MANIFEST }, /* RT_MANIFEST (24) */
#endif
  { "MENU", MENU },
  { "MENUBARBREAK", MENUBARBREAK },
  { "MENUBREAK", MENUBREAK },
  { "MENUEX", MENUEX },
  { "MENUITEM", MENUITEM },
  { "MESSAGETABLE", MESSAGETABLE },
  { "MOVEABLE", MOVEABLE },
  { "NOINVERT", NOINVERT },
  { "NOT", NOT },
#if 0
  { "PLUGPLAY", PLUGPLAY }, /* RT_PLUGPLAY (19) */
#endif
  { "POPUP", POPUP },
  { "PRELOAD", PRELOAD },
  { "PRODUCTVERSION", PRODUCTVERSION },
  { "PURE", PURE },
  { "PUSHBOX", PUSHBOX },
  { "PUSHBUTTON", PUSHBUTTON },
  { "RADIOBUTTON", RADIOBUTTON },
  { "RCDATA", RCDATA },
  { "RTEXT", RTEXT },
  { "SCROLLBAR", SCROLLBAR },
  { "SEPARATOR", SEPARATOR },
  { "SHIFT", SHIFT },
  { "STATE3", STATE3 },
  { "STRINGTABLE", STRINGTABLE },
  { "STYLE", STYLE },
#if 0
  { "TOOLBAR", TOOLBAR },
#endif
  { "USERBUTTON", USERBUTTON },
  { "VALUE", VALUE },
  { "VERSION", VERSIONK },
  { "VERSIONINFO", VERSIONINFO },
  { "VIRTKEY", VIRTKEY },
#if 0
  { "VXD", VXD }, /* RT_VXD 20 */
#endif
  { NULL, 0 },
};

/* Lexical scanner helpers.  */
static int rclex_lastch = -1;
static size_t rclex_tok_max = 0;
static size_t rclex_tok_pos = 0;
static char *rclex_tok_cur = NULL;

/* Local functions.  */

static void cpp_line (const char *);
static char *handle_quotes (const char *, unsigned long *);
static char *get_string (int);
static void rclex_backch (int);
static int rclex_readch (void);
static int rclex_peekch (void);
static void rclex_append_char_tok (int);
static void rclex_cleartok (void);
static void rclex_delelete_char_tok (void);

/* The lexer function called by yyparse.  */
int yylex(void)
{
  int ch;
  do
    {
      do
	{
	  rclex_cleartok();
	  ch = rclex_readch ();
	  if (ch == -1)
	    return -1;
	  if (ch == '\n')
	    ++rc_lineno;
	}
      while (ch >= 0 && ch <= 0x20);

      switch ( ch )
	{
	case '#':
	  while ((ch = rclex_peekch()) != -1 && ch != '\n')
	    rclex_readch();
	  cpp_line (rclex_tok_cur);
	  ch = IGNORED_TOKEN;
	  break;
	case '{':
	  ch = MAYBE_IGNORE (BEG); break;
	case '}':
	  ch = MAYBE_IGNORE (END); break;
	case '0': case '1': case '2': case '3': case '4':
	case '5': case '6': case '7': case '8': case '9':
	  ch = rclex_peekch ();
	  if (ch == 'x' || ch == 'X')
	    rclex_readch();
	  while ((ch = rclex_peekch ()) != -1)
	    {
	      if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z')
		  || (ch >='a' && ch <= 'f'))
		{
		  rclex_readch ();
		}
	      else
		break;
	    }
	  yylval.i.val = strtoul (rclex_tok_cur, 0, 0);
	  if (ch == 'L' || ch == 'l')
	    {
	      yylval.i.dword = 1;
	      rclex_readch ();
	    }
	  else
	    yylval.i.dword = 0;
	  ch = MAYBE_IGNORE (NUMBER);
	  break;
	case '"':
	  while ((ch = rclex_peekch()) != -1)
	    {
	      if (ch == '\r' || ch == '\n')
		break;
	      if (ch == '\\')
		{
		  rclex_readch();
		  ch = rclex_peekch();
		  if (ch == 0 || ch == -1)
		    break;
		  if (ch == '\r' || ch == '\n')
		    {
		      rclex_delelete_char_tok(); /* Remove backslash from input.  */
		      rclex_readch();
		      if (ch == '\r')
			{
			  ch = rclex_peekch();
			  if (ch == '\n')
			    rclex_readch();
			}
		    }
		  else
		    {
		      rclex_readch();
		    }
		}
	      else
	      {
		rclex_readch();
		if (ch == '"')
		  break;
	      }
	    }
	  ch = MAYBE_IGNORE ((! rcdata_mode ? QUOTEDSTRING : SIZEDSTRING));
	  if (ch != IGNORED_TOKEN)
	    {
	      char *s;
	      unsigned long length;

	      s = handle_quotes (rclex_tok_cur, &length);
	      if (! rcdata_mode)
		yylval.s = s;
	      else
		{
		  yylval.ss.length = length;
		  yylval.ss.s = s;
		}
	    }
	  break;
	default:
	  if ((ch >='a' && ch <='z') || (ch >='A' && ch <= 'Z') || ch=='_' || ch=='$')
	    {
	      ch = rclex_peekch ();
	      while ((ch >='a' && ch <='z') || (ch >='A' && ch <= 'Z') || ch == '_' || ch == '$'
		      || (ch >='0' && ch <='9'))
		{
		  rclex_readch ();
		  ch = rclex_peekch ();
		}
	      ch = rclex_translatekeyword (rclex_tok_cur);
	      ch = MAYBE_IGNORE (ch);
	      if (ch == STRING)
		{
		  char *s;
		  s = get_string (strlen (rclex_tok_cur) + 1);
		  strcpy (s, rclex_tok_cur);
		  yylval.s = s;
		}
	      else if (ch == BLOCK)
	      {
		int saved_rc_data = rcdata_mode;
		int lextok;
		rcdata_mode = 0; /* Force to scan strings */
		lextok = yylex();
		rcdata_mode = saved_rc_data;
		
		if (lextok != STRING && lextok != QUOTEDSTRING)
		  {
		    rcparse_warning ("BLOCK expects a string as argument.");
		    yylval.s = "";
		  }
		if (!strcmp (yylval.s, "StringFileInfo"))
		  ch = BLOCKSTRINGFILEINFO;
		else if (!strcmp(yylval.s, "VarFileInfo"))
		  ch =BLOCKVARFILEINFO;
	      }
	      break;
	    }
	  ch = MAYBE_IGNORE (ch);
	  break;
	}
    }
  while (ch == IGNORED_TOKEN);
  return ch;
}

/* Find a keyword and return its ident.  */

static int
rclex_translatekeyword (const char *key)
{
  const struct rclex_keywords *kw = &keywds[0];
  if (!key || *key == 0 || !(key[0] >= 'A' && key[0] <= 'Z'))
    return STRING;
  while (kw->name != NULL)
    {
      if (strcmp(kw->name, key) == 0)
	return kw->tok;
      ++kw;
    }
  return STRING;
}

/* Handle a C preprocessor line.  */

static void
cpp_line (const char *s)
{
  int line;
  char *send, *fn;

  ++s;
  while (ISSPACE (*s))
    ++s;
  
  line = strtol (s, &send, 0);
  if (*send != '\0' && ! ISSPACE (*send))
    return;

  /* Subtract 1 because we are about to count the newline.  */
  rc_lineno = line - 1;

  s = send;
  while (ISSPACE (*s))
    ++s;

  if (*s != '"')
    return;

  ++s;
  send = strchr (s, '"');
  if (send == NULL)
    return;

  fn = (char *) xmalloc (send - s + 1);
  strncpy (fn, s, send - s);
  fn[send - s] = '\0';

  free (rc_filename);
  rc_filename = fn;

  if (!initial_fn)
    {
      initial_fn = xmalloc (strlen (fn) + 1);
      strcpy (initial_fn, fn);
    }

  /* Allow the initial file, regardless of name.  Suppress all other
     files if they end in ".h" (this allows included "*.rc").  */
  if (strcmp (initial_fn, fn) == 0
      || strcmp (fn + strlen (fn) - 2, ".h") != 0)
    suppress_cpp_data = 0;
  else
    suppress_cpp_data = 1;
}

/* Handle a quoted string.  The quotes are stripped.  A pair of quotes
   in a string are turned into a single quote.  Adjacent strings are
   merged separated by whitespace are merged, as in C.  */

static char *
handle_quotes (const char *input, unsigned long *len)
{
  char *ret, *s;
  const char *t;
  int ch;
  int num_xdigits;

  ret = get_string (strlen (input) + 1);

  s = ret;
  t = input;
  if (*t == '"')
    ++t;
  while (*t != '\0')
    {
      if (*t == '\\')
	{
	  ++t;
	  switch (*t)
	    {
	    case '\0':
	      rcparse_warning ("backslash at end of string");
	      break;

	    case '\"':
	      rcparse_warning ("use \"\" to put \" in a string");
	      break;

	    case 'a':
	      *s++ = ESCAPE_B; /* Strange, but true...  */
	      ++t;
	      break;

	    case 'b':
	      *s++ = ESCAPE_B;
	      ++t;
	      break;

	    case 'f':
	      *s++ = ESCAPE_F;
	      ++t;
	      break;

	    case 'n':
	      *s++ = ESCAPE_N;
	      ++t;
	      break;

	    case 'r':
	      *s++ = ESCAPE_R;
	      ++t;
	      break;

	    case 't':
	      *s++ = ESCAPE_T;
	      ++t;
	      break;

	    case 'v':
	      *s++ = ESCAPE_V;
	      ++t;
	      break;

	    case '\\':
	      *s++ = *t++;
	      break;

	    case '0': case '1': case '2': case '3':
	    case '4': case '5': case '6': case '7':
	      ch = *t - '0';
	      ++t;
	      if (*t >= '0' && *t <= '7')
		{
		  ch = (ch << 3) | (*t - '0');
		  ++t;
		  if (*t >= '0' && *t <= '7')
		    {
		      ch = (ch << 3) | (*t - '0');
		      ++t;
		    }
		}
	      *s++ = ch;
	      break;

	    case 'x':
	      ++t;
	      ch = 0;
	      /* We only handle single byte chars here.  Make sure
		 we finish an escape sequence like "/xB0ABC" after
		 the first two digits.  */
              num_xdigits = 2;
 	      while (num_xdigits--)
		{
		  if (*t >= '0' && *t <= '9')
		    ch = (ch << 4) | (*t - '0');
		  else if (*t >= 'a' && *t <= 'f')
		    ch = (ch << 4) | (*t - 'a' + 10);
		  else if (*t >= 'A' && *t <= 'F')
		    ch = (ch << 4) | (*t - 'A' + 10);
		  else
		    break;
		  ++t;
		}
	      *s++ = ch;
	      break;

	    default:
	      rcparse_warning ("unrecognized escape sequence");
	      *s++ = '\\';
	      *s++ = *t++;
	      break;
	    }
	}
      else if (*t != '"')
	*s++ = *t++;
      else if (t[1] == '\0')
	break;
      else if (t[1] == '"')
	{
	  *s++ = '"';
	  t += 2;
	}
      else
	{
	  ++t;
	  assert (ISSPACE (*t));
	  while (ISSPACE (*t))
	    {
	      if ((*t) == '\n')
		++rc_lineno;
	      ++t;
	    }
	  if (*t == '\0')
	    break;
	  assert (*t == '"');
	  ++t;
	}
    }

  *s = '\0';

  *len = s - ret;

  return ret;
}

/* Allocate a string of a given length.  */
static char *
get_string (int len)
{
  struct alloc_string *as;

  as = (struct alloc_string *) xmalloc (sizeof *as);
  as->s = xmalloc (len);

  as->next = strings;
  strings = as;

  return as->s;
}

/* Discard all the strings we have allocated.  The parser calls this
   when it no longer needs them.  */

void
rcparse_discard_strings (void)
{
  struct alloc_string *as;

  as = strings;
  while (as != NULL)
    {
      struct alloc_string *n;

      free (as->s);
      n = as->next;
      free (as);
      as = n;
    }

  strings = NULL;
}

/* Enter rcdata mode.  */

void
rcparse_rcdata (void)
{
  rcdata_mode = 1;
}

/* Go back to normal mode from rcdata mode.  */

void
rcparse_normal (void)
{
  rcdata_mode = 0;
}

/* Add a character to end of token buffer.  */

static void
rclex_append_char_tok (int ch)
{
  if (!rclex_tok_cur || rclex_tok_max <= rclex_tok_pos)
    {
      char *h = (char *) xmalloc (rclex_tok_max + 9);
      if (!h)
	abort ();
      if (rclex_tok_cur)
	{
	  memcpy (h, rclex_tok_cur, rclex_tok_pos + 1);
	  free (rclex_tok_cur);
	}
      rclex_tok_max += 8;
      rclex_tok_cur = h;
    }
  if (ch != -1 && ch != 0)
    rclex_tok_cur[rclex_tok_pos++] = (char) ch;
  rclex_tok_cur[rclex_tok_pos] = 0;
}

/* Clear token buffer.  */

static void
rclex_cleartok (void)
{
  rclex_tok_pos=0;
  
  /* Force token-buffer initialization.  */
  if (!rclex_tok_cur)
    rclex_append_char_tok (0);
  rclex_tok_pos=0;
  rclex_tok_cur[0] = 0;
}

/* Remove - if present - a character from token buffer right-hand
   side.  */

static void
rclex_delelete_char_tok (void)
{
  /* Force token-buffer initialization.  */
  if (!rclex_tok_cur)
    rclex_append_char_tok (0);
  if (rclex_tok_pos > 0)
    rclex_tok_cur[--rclex_tok_pos] = 0;
}

/* Read next to be processed character from input stream.
   If there is no further character to be processed, return
   -1 to indicate end of stream.  */

static int
rclex_peekch (void)
{
  int ch;
  if (rclex_lastch != -1)
    return rclex_lastch;

  ch = rclex_readch ();
  rclex_backch (ch);
  return ch;
}

/* Put the character back to input stream to be processed
   by next call to rclex_readch.
   Ignore character, if it is EOF or zero.
   Additionally remove one position in token buffer.  */

static void
rclex_backch (int ch)
{
  if (ch == -1 || ch == 0)
    return;
  if (rclex_lastch != -1)
    rcparse_warning ("rclex: Warning buffer underflow.\n");
  rclex_lastch = ch;
  rclex_delelete_char_tok ();
}

/* Read a character from input stream yyin or back-buffer.
   If there is no character left, return -1 to indicate
   end of input stream.
   Additionally put this character into the token buffer.  */

static int
rclex_readch (void)
{
  int ret = -1;

  if (rclex_lastch != -1)
    {
      ret = rclex_lastch;
      rclex_lastch = -1;
    }
  else
    {
      do
        {
          char ch;
	  
	  if (!yyin || feof (yyin))
	    break;
	  if (fread (&ch, 1, 1,yyin) != 1)
	    break;
	  ret = ((int) ch)&0xff;
        }
      while (ret == 0 || ret == '\r');
  }
  rclex_append_char_tok (ret);
  return ret;
}

  reply	other threads:[~2007-04-23 12:56 UTC|newest]

Thread overview: 39+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-04-11 13:43 PATCH: w64 native support Kai Tietz
2007-04-11 13:58 ` H. J. Lu
2007-04-11 14:07   ` H. J. Lu
2007-04-11 18:22     ` PATCH: windres Kai Tietz
2007-04-12 15:55       ` H. J. Lu
2007-04-12 16:51         ` Kai Tietz
2007-04-12 18:03           ` H. J. Lu
2007-04-13 14:41             ` Kai Tietz
2007-04-13 14:49               ` H. J. Lu
2007-04-16 10:05                 ` Kai Tietz
2007-04-16 21:59                   ` Christopher Faylor
2007-04-16 22:20                     ` H. J. Lu
2007-04-17 10:59                       ` Kai Tietz
2007-04-18  4:34                         ` Christopher Faylor
2007-04-18  9:49                           ` H. J. Lu
2007-04-20 13:34                             ` Kai Tietz
2007-04-20 13:35                               ` H. J. Lu
2007-04-20 13:54                                 ` Kai Tietz
2007-04-20 14:03                                   ` H. J. Lu
2007-04-20 13:40                               ` Dave Korn
2007-04-20 13:51                                 ` Kai Tietz
2007-04-20 13:58                                   ` Dave Korn
2007-04-23 12:26                                     ` Kai Tietz
2007-04-23 12:44                                       ` Christopher Faylor
2007-04-23 13:51                                         ` Kai Tietz [this message]
2007-04-23 14:23                                           ` Christopher Faylor
2007-04-23 14:36                                             ` Dave Korn
2007-04-23 14:46                                               ` Kai Tietz
2007-04-23 14:50                                                 ` Christopher Faylor
2007-04-18 11:59     ` PATCH: w64 native support Kai Tietz
2007-06-29  5:37       ` NightStrike
2007-07-12  7:30       ` Nick Clifton
2007-07-24  8:00         ` NightStrike
2007-04-11 14:57   ` Kai Tietz
2007-04-11 15:17     ` Daniel Jacobowitz
2007-04-11 15:24       ` Kai Tietz
2007-04-11 15:43         ` Daniel Jacobowitz
2007-04-11 15:49           ` Kai Tietz
2007-04-11 17:34             ` Daniel Jacobowitz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=OF87B638C3.6DB54863-ONC12572C6.004648B2-C12572C6.00470D13@onevision.de \
    --to=kai.tietz@onevision.com \
    --cc=binutils@sourceware.org \
    --cc=cgf-use-the-mailinglist-please@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).