# Install bcftools, its manpage, bcf-fix.pl, vcfutils.pl, and new examples.
[samtools.git] / sam_header.c
index a119c02b9c4cfaa0e6c4251454fd86cd12db3743..05d75deb2c4ced014c6ae5f8612260d05b34660a 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;
 };
@@ -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);
 
@@ -539,7 +572,8 @@ void *sam_header_parse2(const char *headerText)
     {
         hline = sam_header_line_parse(buf);
         if ( hline && sam_header_line_validate(hline) )
-            hlines = list_append(hlines, 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);