diff --git a/tutorial/Makefile b/tutorial/Makefile
index bab1e5c2faf720c6b3a5e879427a0b926b3caa3e..4a07031ef45e36c1b968f9a4541cb7a72ea4e915 100644
--- a/tutorial/Makefile
+++ b/tutorial/Makefile
@@ -9,16 +9,16 @@ pike=pike
 .DUMMY: 
 
 tutorial.html: .DUMMY $(SRCFILES)
-	$(pike) ./wmmltohtml2 <tutorial.wmml html tutorial
+	$(pike) ./wmmltohtml2 tutorial.wmml html tutorial
 
 tutorial_onepage.html: .DUMMY  $(SRCFILES)
-	$(pike) ./wmmltohtml2 <tutorial.wmml html_onepage tutorial_onepage
+	$(pike) ./wmmltohtml2 tutorial.wmml html_onepage tutorial_onepage
 
 tut.html: .DUMMY $(SRCFILES)
-	$(pike) ./wmmltohtml2 <tutorial.wmml sitebuilder tut
+	$(pike) ./wmmltohtml2 tutorial.wmml sitebuilder tut
 
 manpages: .DUMMY $(SRCFILES)
-	$(pike) ./wmmltohtml2 <tutorial.wmml manpages man/man
+	$(pike) ./wmmltohtml2 tutorial.wmml manpages man/man
 
 Image.wmml : 
 	(cd ../src/modules/Image; make wmml pike="$(pike)")
@@ -27,10 +27,10 @@ Mysql.wmml :
 	$(pike) ../bin/mkwmml.pike ../src/modules/Mysql/mysql.c >Mysql.wmml
 
 the_image_module_onepage.html: Image.wmml the_image_module.wmml
-	$(pike) ./wmmltohtml2 <the_image_module.wmml html_onepage the_image_module_onepage
+	$(pike) ./wmmltohtml2 the_image_module.wmml html_onepage the_image_module_onepage
 
 the_image_module.html: Image.wmml the_image_module.wmml
-	$(pike) ./wmmltohtml2 <the_image_module.wmml html the_image_module
+	$(pike) ./wmmltohtml2 the_image_module.wmml html the_image_module
 
 clean:
 	rm *.html *.md illustration_cache illustration*.gif 
diff --git a/tutorial/Sgml.pmod b/tutorial/Sgml.pmod
index db219fc8f116c252c0df9f5e7fddb1f90bb97718..4cf97b4b2ad57b3a4d56a3816f2390ca419a26da 100644
--- a/tutorial/Sgml.pmod
+++ b/tutorial/Sgml.pmod
@@ -15,10 +15,23 @@ class Tag
 
   string location()
   {
-    return "pos "+pos+" in file "+file;
+#if 1
+    if(file && file!="stdin")
+    {
+      Stdio.File f=Stdio.File();
+      if(f->open(file,"r"))
+      {
+	string *x=f->read(pos-1)/"\n";
+	return sprintf("line %d col %d in file %s",sizeof(x)+1,strlen(x[-1])+1,file);
+      }
+    }
+#endif
+    return "pos "+pos+" in file "+file; 
   }
 
-  void create(string t, void|mapping p, void|int po, 
+  void create(string t,
+	      void|mapping p,
+	      void|int po, 
 	      void|array(object|string) d, void|string f)
   {
     tag=t;
diff --git a/tutorial/Wmml.pmod b/tutorial/Wmml.pmod
index 773254aae9f5d0a25d12e31568f3c3979995e5b1..5c67526dd11f3381f27d02544f6df454afd8f885 100644
--- a/tutorial/Wmml.pmod
+++ b/tutorial/Wmml.pmod
@@ -6,8 +6,30 @@ import Sgml;
 
 SGML low_make_concrete_wmml(SGML data);
 
+class Trace
+{
+  Trace prev;
+  Tag tag;
+
+  void create(Trace p, Tag t)
+  {
+    prev=p;
+    tag=t;
+  }
+
+  string dump()
+  {
+    return 
+      (tag ? "  In tag "+(tag->tag=="anchor"?tag->tag+" (name="+tag->params->name+")":tag->tag)+" near "+tag->location()+"\n" : "")+
+      (prev?prev->dump():"");
+  }
+}
+
 
-static private int verify_any(SGML data, string in, string input, string input_name)
+static private int verify_any(SGML data,
+			      Trace in,
+			      string input,
+			      string input_name)
 {
   int i=1;
   foreach(data,mixed x)
@@ -19,14 +41,14 @@ static private int verify_any(SGML data, string in, string input, string input_n
 	if(input[x->pos-1]!='<')
 	{
 	  werror("Location out of sync in tag "+x->tag+" near "+x->location()+"\n");
-	  werror(in);
+	  werror(in->dump());
 	}
       }
      
       if(strlen(x->tag) && x->tag[0]=='/')
       {
 	werror("Unmatched "+x->tag+" near "+x->location()+"\n");
-	werror(in);
+	werror(in->dump());
 	i=0;
 	continue;
       }
@@ -34,7 +56,7 @@ static private int verify_any(SGML data, string in, string input, string input_n
       {
       default:
 	werror("Unknown tag "+x->tag+" near "+x->location()+".\n");
-	werror(in);
+	werror(in->dump());
 	i=0;
 	break;
 
@@ -99,7 +121,7 @@ static private int verify_any(SGML data, string in, string input, string input_n
 	if(!x->data)
 	{
 	  werror("Tag "+x->tag+" not closed near "+x->location()+".\n");
-	  werror(in);
+	  werror(in->dump());
 	  i=0;
 	}
 
@@ -121,7 +143,7 @@ static private int verify_any(SGML data, string in, string input, string input_n
 	if(x->data)
 	{
 	  werror("Tag "+x->tag+" should not be closed near "+x->location()+"\n");
-	  werror(in);
+	  werror(in->dump());
 	  i=0;
 	}
       case "p":
@@ -130,7 +152,7 @@ static private int verify_any(SGML data, string in, string input, string input_n
 
       if(x->data)
 	if(!verify_any(x->data,
-		       ("  In tag "+(x->tag=="anchor"?x->tag+" (name="+x->params->name+")":x->tag)+" near "+x->location()+"\n"+in),
+		       Trace(in,x),
 		       input,
 		       input_name))
 	  i=0;
@@ -141,7 +163,7 @@ static private int verify_any(SGML data, string in, string input, string input_n
 
 int verify(SGML data, string input, string input_name)
 {
-  return verify_any(data,"", input, input_name);
+  return verify_any(data,Trace(0,0), input, input_name);
 }
 
 INDEX_DATA collect_index(SGML data, void|INDEX_DATA index,void|mapping taken)
@@ -679,7 +701,7 @@ SGML low_make_concrete_wmml(SGML data)
 			tag->pos,
 			({
 			  Tag("tt",([]),tag->pos,({name})),
-			    })),
+			    }),tag->file),
 		      ", "
 			});
 		}