New upstream release.
[samtools.git] / sam_header.c
index a119c02b9c4cfaa0e6c4251454fd86cd12db3743..f4c8a3bb65d8c52159c16b0a92e1c4d2528e4feb 100644 (file)
@@ -10,6 +10,7 @@ KHASH_MAP_INIT_STR(str, const char *)
 
 struct _HeaderList
 {
+    struct _HeaderList *last;   // Hack: Used and maintained only by list_append_to_end. Maintained in the root node only.
     struct _HeaderList *next;
     void *data;
 };
@@ -37,7 +38,7 @@ const char *o_sq_tags[] = {"AS","M5","UR","SP",NULL};
 const char *r_sq_tags[] = {"SN","LN",NULL};
 const char *u_sq_tags[] = {"SN",NULL};
 
-const char *o_rg_tags[] = {"LB","DS","PU","PI","CN","DT","PL",NULL};
+const char *o_rg_tags[] = {"CN","DS","DT","FO","KS","LB","PG","PI","PL","PU","SM",NULL};
 const char *r_rg_tags[] = {"ID",NULL};
 const char *u_rg_tags[] = {"ID",NULL};
 
@@ -58,6 +59,34 @@ static void debug(const char *format, ...)
     va_end(ap);
 }
 
+#if 0
+// Replaced by list_append_to_end
+static list_t *list_prepend(list_t *root, void *data)
+{
+    list_t *l = malloc(sizeof(list_t));
+    l->next = root;
+    l->data = data;
+    return l;
+}
+#endif
+
+// Relies on the root->last being correct. Do not use with the other list_*
+//  routines unless they are fixed to modify root->last as well.
+static list_t *list_append_to_end(list_t *root, void *data)
+{
+    list_t *l = malloc(sizeof(list_t));
+    l->last = l;
+    l->next = NULL;
+    l->data = data;
+
+    if ( !root )
+        return l;
+
+    root->last->next = l;
+    root->last = l;
+    return root;
+}
+
 static list_t *list_append(list_t *root, void *data)
 {
     list_t *l = root;
@@ -322,7 +351,7 @@ static HeaderLine *sam_header_line_parse(const char *headerLine)
 
     while (*to && *to!='\t') to++;
     if ( to-from != 2 ) {
-               debug("[sam_header_line_parse] expected '@XY', got [%s]\n", headerLine);
+               debug("[sam_header_line_parse] expected '@XY', got [%s]\nHint: The header tags must be tab-separated.\n", headerLine);
                return 0;
        }
     
@@ -345,7 +374,11 @@ static HeaderLine *sam_header_line_parse(const char *headerLine)
         while (*to && *to!='\t') to++;
 
         if ( !required_tags[itype] && !optional_tags[itype] )
+        {
+            // CO is a special case, it can contain anything, including tabs
+            if ( *to ) { to++; continue; }
             tag = new_tag("  ",from,to-1);
+        }
         else
             tag = new_tag(from,from+3,to-1);
 
@@ -530,6 +563,7 @@ void *sam_header_parse2(const char *headerText)
     const char *text;
     char *buf=NULL;
     size_t nbuf = 0;
+       int tovalidate = 0;
 
     if ( !headerText )
                return 0;
@@ -538,8 +572,9 @@ void *sam_header_parse2(const char *headerText)
     while ( (text=nextline(&buf, &nbuf, text)) )
     {
         hline = sam_header_line_parse(buf);
-        if ( hline && sam_header_line_validate(hline) )
-            hlines = list_append(hlines, hline);
+        if ( hline && (!tovalidate || sam_header_line_validate(hline)) )
+            // With too many (~250,000) reference sequences the header parsing was too slow with list_append.
+            hlines = list_append_to_end(hlines, hline);
         else
         {
                        if (hline) sam_header_line_free(hline);