diff macro.c @ 178:0d5b9651b240

Merge Joerg's changes into upstream. (now that they've been thrashed out a bit, include CHANGES entries, etc.)
author David A. Holland
date Fri, 12 Jun 2015 03:05:49 -0400
parents 6119608a9817
children d359d9b86327
line wrap: on
line diff
--- a/macro.c	Fri Jun 12 03:04:48 2015 -0400
+++ b/macro.c	Fri Jun 12 03:05:49 2015 -0400
@@ -28,6 +28,7 @@
  */
 
 #include <stdint.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -38,10 +39,10 @@
 #include "output.h"
 
 struct expansionitem {
-	bool isstring;
+	enum { EI_STRING, EI_PARAM, EI_FILE, EI_LINE } itemtype;
 	union {
-		char *string;
-		unsigned param;
+		char *string;		/* EI_STRING */
+		unsigned param;		/* EI_PARAM */
 	};
 };
 DECLARRAY(expansionitem, static UNUSED);
@@ -76,7 +77,7 @@
 	struct expansionitem *ei;
 
 	ei = domalloc(sizeof(*ei));
-	ei->isstring = true;
+	ei->itemtype = EI_STRING;
 	ei->string = dostrdup(string);
 	return ei;
 }
@@ -88,7 +89,7 @@
 	struct expansionitem *ei;
 
 	ei = domalloc(sizeof(*ei));
-	ei->isstring = true;
+	ei->itemtype = EI_STRING;
 	ei->string = dostrndup(string, len);
 	return ei;
 }
@@ -100,17 +101,45 @@
 	struct expansionitem *ei;
 
 	ei = domalloc(sizeof(*ei));
-	ei->isstring = false;
+	ei->itemtype = EI_PARAM;
 	ei->param = param;
 	return ei;
 }
 
 static
+struct expansionitem *
+expansionitem_create_file(void)
+{
+	struct expansionitem *ei;
+
+	ei = domalloc(sizeof(*ei));
+	ei->itemtype = EI_FILE;
+	return ei;
+}
+
+static
+struct expansionitem *
+expansionitem_create_line(void)
+{
+	struct expansionitem *ei;
+
+	ei = domalloc(sizeof(*ei));
+	ei->itemtype = EI_LINE;
+	return ei;
+}
+
+static
 void
 expansionitem_destroy(struct expansionitem *ei)
 {
-	if (ei->isstring) {
+	switch (ei->itemtype) {
+	    case EI_STRING:
 		dostrfree(ei->string);
+		break;
+	    case EI_PARAM:
+	    case EI_FILE:
+	    case EI_LINE:
+		break;
 	}
 	dofree(ei, sizeof(*ei));
 }
@@ -120,17 +149,23 @@
 expansionitem_eq(const struct expansionitem *ei1,
 		 const struct expansionitem *ei2)
 {
-	if (ei1->isstring != ei2->isstring) {
+	if (ei1->itemtype != ei2->itemtype) {
 		return false;
 	}
-	if (ei1->isstring) {
+	switch (ei1->itemtype) {
+	    case EI_STRING:
 		if (strcmp(ei1->string, ei2->string) != 0) {
 			return false;
 		}
-	} else {
+		break;
+	    case EI_PARAM:
 		if (ei1->param != ei2->param) {
 			return false;
 		}
+		break;
+	    case EI_FILE:
+	    case EI_LINE:
+		break;
 	}
 	return true;
 }
@@ -587,6 +622,24 @@
 }
 
 void
+macro_define_magic(struct place *p, const char *macro)
+{
+	struct macro *m;
+	struct expansionitem *ei;
+
+	m = macro_define_common_start(p, macro, p);
+	if (!strcmp(macro, "__FILE__")) {
+		ei = expansionitem_create_file();
+	}
+	else {
+		assert(!strcmp(macro, "__LINE__"));
+		ei = expansionitem_create_line();
+	}
+	expansionitemarray_add(&m->expansion, ei, NULL);
+	macro_define_common_end(m);
+}
+
+void
 macro_undef(const char *macro)
 {
 	struct macro *m;
@@ -624,7 +677,7 @@
 static struct expstate mainstate;
 
 static void doexpand(struct expstate *es, struct place *p,
-		     char *buf, size_t len);
+		     const char *buf, size_t len);
 
 static
 void
@@ -705,7 +758,7 @@
 
 static
 void
-expand_newarg(struct expstate *es, char *buf, size_t len)
+expand_newarg(struct expstate *es, const char *buf, size_t len)
 {
 	char *text;
 
@@ -715,7 +768,7 @@
 
 static
 void
-expand_appendarg(struct expstate *es, char *buf, size_t len)
+expand_appendarg(struct expstate *es, const char *buf, size_t len)
 {
 	unsigned num;
 	char *text;
@@ -742,6 +795,7 @@
 	char *arg;
 	char *ret;
 	unsigned numargs, numparams;
+	char numbuf[64];
 
 	numargs = stringarray_num(&es->args);
 	numparams = stringarray_num(&es->curmacro->params);
@@ -766,11 +820,20 @@
 	num = expansionitemarray_num(&es->curmacro->expansion);
 	for (i=0; i<num; i++) {
 		ei = expansionitemarray_get(&es->curmacro->expansion, i);
-		if (ei->isstring) {
+		switch (ei->itemtype) {
+		    case EI_STRING:
 			len += strlen(ei->string);
-		} else {
+			break;
+		    case EI_PARAM:
 			arg = stringarray_get(&es->args, ei->param);
 			len += strlen(arg);
+			break;
+		    case EI_FILE:
+			len += strlen(place_getname(p)) + 2;
+			break;
+		    case EI_LINE:
+			len += snprintf(numbuf, sizeof(numbuf), "%u", p->line);
+			break;
 		}
 	}
 
@@ -778,11 +841,23 @@
 	*ret = '\0';
 	for (i=0; i<num; i++) {
 		ei = expansionitemarray_get(&es->curmacro->expansion, i);
-		if (ei->isstring) {
+		switch (ei->itemtype) {
+		    case EI_STRING:
 			strcat(ret, ei->string);
-		} else {
+			break;
+		    case EI_PARAM:
 			arg = stringarray_get(&es->args, ei->param);
 			strcat(ret, arg);
+			break;
+		    case EI_FILE:
+			strcat(ret, "\"");
+			strcat(ret, place_getname(p));
+			strcat(ret, "\"");
+			break;
+		    case EI_LINE:
+			snprintf(numbuf, sizeof(numbuf), "%u", p->line);
+			strcat(ret, numbuf);
+			break;
 		}
 	}
 
@@ -846,7 +921,8 @@
 
 static
 void
-expand_got_ws(struct expstate *es, struct place *p, char *buf, size_t len)
+expand_got_ws(struct expstate *es, struct place *p,
+	      const char *buf, size_t len)
 {
 	switch (es->state) {
 	    case ES_NORMAL:
@@ -868,7 +944,8 @@
 
 static
 void
-expand_got_word(struct expstate *es, struct place *p, char *buf, size_t len)
+expand_got_word(struct expstate *es, struct place *p,
+		const char *buf, size_t len)
 {
 	struct macro *m;
 
@@ -917,7 +994,8 @@
 
 static
 void
-expand_got_lparen(struct expstate *es, struct place *p, char *buf, size_t len)
+expand_got_lparen(struct expstate *es, struct place *p,
+		  const char *buf, size_t len)
 {
 	switch (es->state) {
 	    case ES_NORMAL:
@@ -940,7 +1018,8 @@
 
 static
 void
-expand_got_rparen(struct expstate *es, struct place *p, char *buf, size_t len)
+expand_got_rparen(struct expstate *es, struct place *p,
+		  const char *buf, size_t len)
 {
 	switch (es->state) {
 	    case ES_NORMAL:
@@ -975,7 +1054,8 @@
 
 static
 void
-expand_got_comma(struct expstate *es, struct place *p, char *buf, size_t len)
+expand_got_comma(struct expstate *es, struct place *p,
+		 const char *buf, size_t len)
 {
 	switch (es->state) {
 	    case ES_NORMAL:
@@ -1003,7 +1083,8 @@
 
 static
 void
-expand_got_other(struct expstate *es, struct place *p, char *buf, size_t len)
+expand_got_other(struct expstate *es, struct place *p,
+		 const char *buf, size_t len)
 {
 	switch (es->state) {
 	    case ES_NORMAL:
@@ -1055,7 +1136,7 @@
 
 static
 void
-doexpand(struct expstate *es, struct place *p, char *buf, size_t len)
+doexpand(struct expstate *es, struct place *p, const char *buf, size_t len)
 {
 	char *s;
 	size_t x;
@@ -1144,7 +1225,7 @@
 }
 
 char *
-macroexpand(struct place *p, char *buf, size_t len, bool honordefined)
+macroexpand(struct place *p, const char *buf, size_t len, bool honordefined)
 {
 	struct expstate es;
 	char *ret;
@@ -1166,10 +1247,30 @@
 }
 
 void
-macro_sendline(struct place *p, char *buf, size_t len)
+macro_sendline(struct place *p, const char *buf, size_t len)
 {
 	doexpand(&mainstate, p, buf, len);
-	output(p, "\n", 1);
+	switch (mainstate.state) {
+	    case ES_NORMAL:
+		/*
+		 * If we were sent a blank line, don't emit a newline
+		 * for it. This matches the prior behavior of tradcpp.
+		 */
+		if (len > 0) {
+			output(p, "\n", 1);
+		}
+		break;
+	    case ES_WANTLPAREN:
+	    case ES_NOARG:
+	    case ES_HAVEARG:
+		/*
+		 * Apparently to match gcc's -traditional behavior we
+		 * need to emit a space for each newline that appears
+		 * while processing macro args.
+		 */
+		expand_got_ws(&mainstate, p, " ", 1);
+		break;
+	}
 }
 
 void