Index: trunk/Ohana/src/opihi/cmd.data/create.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/create.c	(revision 41164)
+++ trunk/Ohana/src/opihi/cmd.data/create.c	(revision 41269)
@@ -7,4 +7,31 @@
   Vector *vec;
   
+  // create a vector of empty strings
+  if ((N = get_argument (argc, argv, "-str"))) {
+    remove_argument (N, &argc, argv);
+
+    char *stringValue = NULL;
+    if ((N = get_argument (argc, argv, "-value"))) {
+      remove_argument (N, &argc, argv);
+      stringValue = strcreate (argv[N]);
+      remove_argument (N, &argc, argv);
+    }
+
+    if (argc != 3) {
+      gprint (GP_ERR, "USAGE: create vector Nelements -value word\n");
+      return (FALSE);
+    }
+
+    if ((vec = SelectVector (argv[1], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+    int Nelements = atoi (argv[2]);
+
+    // a newly reset vector has NULL-valued pointers
+    ResetVector (vec, OPIHI_STR, Nelements);
+    for (int i = 0; i < Nelements; i++) {
+      vec[0].elements.Str[i] = stringValue ? strcreate (stringValue) : strcreate ("");
+    }
+    return TRUE;
+  }
+
   INT = FALSE;
   if ((N = get_argument (argc, argv, "-int"))) {
@@ -16,4 +43,5 @@
     gprint (GP_ERR, "USAGE: create vector start end [delta] [-int]\n");
     gprint (GP_ERR, " -int : resulting vector is integer type (delta must be integer)\n");
+    gprint (GP_ERR, " -str : resulting vector is string type (only give number of elements)\n");
     return (FALSE);
   }
Index: trunk/Ohana/src/opihi/cmd.data/list_vectors.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/list_vectors.c	(revision 41164)
+++ trunk/Ohana/src/opihi/cmd.data/list_vectors.c	(revision 41269)
@@ -32,16 +32,26 @@
   }
 
-  if (vec->type == OPIHI_FLT) {
-    if (Variable) {
-      set_str_variable (Variable, "FLT");
-    } else {
-      gprint (GP_LOG, "%s : FLT\n", argv[1]);
-    }
-  } else {
-    if (Variable) {
-      set_str_variable (Variable, "INT");
-    } else {
-      gprint (GP_LOG, "%s : INT\n", argv[1]);
-    }
+  switch (vec->type) {
+    case OPIHI_FLT:
+      if (Variable) {
+	set_str_variable (Variable, "FLT");
+      } else {
+	gprint (GP_LOG, "%s : FLT\n", argv[1]);
+      }
+      break;
+    case OPIHI_INT:
+      if (Variable) {
+	set_str_variable (Variable, "INT");
+      } else {
+	gprint (GP_LOG, "%s : INT\n", argv[1]);
+      }
+      break;
+    case OPIHI_STR:
+      if (Variable) {
+	set_str_variable (Variable, "STR");
+      } else {
+	gprint (GP_LOG, "%s : STR\n", argv[1]);
+      }
+      break;
   }
   if (Variable) free (Variable);
Index: trunk/Ohana/src/opihi/cmd.data/print_vectors.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/print_vectors.c	(revision 41164)
+++ trunk/Ohana/src/opihi/cmd.data/print_vectors.c	(revision 41269)
@@ -56,7 +56,11 @@
 	if (vec[i][0].type == OPIHI_FLT) {
 	  gprint (GP_LOG, "%f ", vec[i][0].elements.Flt[j]);
-	} else {
+	} 
+	if (vec[i][0].type == OPIHI_INT) {
 	  gprint (GP_LOG, OPIHI_INT_FMT" ", vec[i][0].elements.Int[j]);
-	}
+	} 
+	if (vec[i][0].type == OPIHI_STR) {
+	  gprint (GP_LOG, "%s ", vec[i][0].elements.Str[j]);
+	} 
       }
     }
Index: trunk/Ohana/src/opihi/cmd.data/read_vectors.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/read_vectors.c	(revision 41164)
+++ trunk/Ohana/src/opihi/cmd.data/read_vectors.c	(revision 41269)
@@ -35,5 +35,5 @@
 
 // vector types
-enum {COLTYPE_NONE, COLTYPE_FLT, COLTYPE_INT, COLTYPE_TIME, COLTYPE_CHAR};
+enum {COLTYPE_NONE, COLTYPE_FLT, COLTYPE_INT, COLTYPE_TIME, COLTYPE_CHAR, COLTYPE_STR};
 
 static int      Nvec     = 0;
@@ -91,6 +91,7 @@
     gprint (GP_ERR, "     -skip N : skip N lines before reading\n");
     gprint (GP_ERR, "     column names may include a type: name:type\n");
-    gprint (GP_ERR, "       type is int, float, char, time\n");
+    gprint (GP_ERR, "       type is int, float, char, str, time\n");
     gprint (GP_ERR, "       for char, values are placed into a list $name:0 - $name:n\n");
+    gprint (GP_ERR, "       for str, values are placed into a string-typed vector\n");
     gprint (GP_ERR, "       for time, values are human-readable date/time strings YYYY/MM/DD,hh:mm:ss\n");
     gprint (GP_ERR, "       the resulting vector is a float based on the TIMEFORMAT, TIMEREF values\n");
@@ -152,4 +153,5 @@
       if (!strcasecmp(ptr, "int"))   { coltype[i] = COLTYPE_INT; }
       if (!strcasecmp(ptr, "char"))  { coltype[i] = COLTYPE_CHAR; }
+      if (!strcasecmp(ptr, "str"))   { coltype[i] = COLTYPE_STR; }
       if (!strcasecmp(ptr, "time"))  { coltype[i] = COLTYPE_TIME; }
       if (!coltype[i]) goto bad_colname;
@@ -213,4 +215,7 @@
 	// note that COLTYPE_TIME is a type of float
 	ResetVector (vec[i], OPIHI_FLT, NELEM);
+	break;
+      case COLTYPE_STR:
+	ResetVector (vec[i], OPIHI_STR, NELEM);
 	break;
       case COLTYPE_CHAR:
@@ -311,4 +316,20 @@
 	      break;
 	    }
+	  case COLTYPE_STR:
+	    {
+	      // I need to get an isolated word in 'value' with the string value of this field 
+	      char *ptr = IsCSV ? ptrparse_csv (col[i], c0) : ptrparse (col[i], c0);
+	      char *value = NULL;
+	      if (IsCSV) {
+		char *end = parse_nextword_csv (ptr);
+		if (end) {
+		  value = end ? strncreate (ptr, end - ptr) : strcreate (ptr);
+		}
+	      } else {
+		value = thisword(ptr);
+	      }
+	      vec[i][0].elements.Str[Nelem] = value; // needs to be freed later.
+	      break;
+	    }
 	  case COLTYPE_FLT:
 	    readStatus = IsCSV ? dparse_csv (&dvalue, col[i], c0) : dparse (&dvalue, col[i], c0);
@@ -348,4 +369,7 @@
 	      ResetVector (vec[i], OPIHI_FLT, NELEM);
 	      break;
+	    case COLTYPE_STR:
+	      ResetVector (vec[i], OPIHI_STR, NELEM);
+	      break;
 	    case COLTYPE_CHAR:
 	    default:
@@ -369,4 +393,7 @@
 	ResetVector (vec[i], OPIHI_FLT, Nelem);
 	break;
+      case COLTYPE_STR:
+	ResetVector (vec[i], OPIHI_STR, Nelem);
+	break;
       case COLTYPE_CHAR:
 	sprintf (varname, "%s:n", listname[i]);
@@ -469,6 +496,10 @@
   }
 
-  // if CharAsVectors, char fields will be saved as vectors NAME:0 -- NAME:n for n characters
-  // else char fields will be saved as $NAME:0 - $NAME:m for m rows
+  // by default, we now store a string-type field as a string-type vector.
+
+  // if CharAsList is selected (and My < 10000), char fields will be saved as $NAME:0 - $NAME:m for m rows
+
+  // if CharAsVectors is selected, char fields will be saved as vectors NAME:0 -- NAME:n for n characters
+
   // if (Ny > 10000), force CharAsVectors
   int CharAsVectors = FALSE;
@@ -476,4 +507,9 @@
     remove_argument (N, &argc, argv);
     CharAsVectors = TRUE;
+  }
+  int CharAsList = FALSE;
+  if ((N = get_argument (argc, argv, "-char-list"))) {
+    remove_argument (N, &argc, argv);
+    CharAsList = TRUE;
   }
 
@@ -651,26 +687,46 @@
     if (!FITS_TRANSPOSE) {
       // read string column into a list rather than a vector
-      if (!strcmp (type, "char") && !CharAsVectors && (Ny < 3000)) {
-	char *fieldName = argv[i];
-	char *Ptr = data;
-	char varname[1024];  // used as a buffer for the names of string fields
-	for (j = 0; j < Ny; j++) {
-	  set_list_varname (varname, fieldName, j, FALSE);
-	  char *value = strncreate (&Ptr[j*Nval], Nval);
-	  // replace instances of $ with _
-	  char *p = strchr (value, '$');
-	  while (p) { 
-	    *p = '_';
-	    p = strchr (p, '$');
+      if (!strcmp (type, "char")) {
+	// save char-type field as a List:
+	if (CharAsList && (Ny < 3000)) {
+	  char *fieldName = argv[i];
+	  char *Ptr = data;
+	  char varname[1024];  // used as a buffer for the names of string fields
+	  for (j = 0; j < Ny; j++) {
+	    set_list_varname (varname, fieldName, j, FALSE);
+	    char *value = strncreate (&Ptr[j*Nval], Nval);
+	    // replace instances of $ with _
+	    char *p = strchr (value, '$');
+	    while (p) { 
+	      *p = '_';
+	      p = strchr (p, '$');
+	    }
+	    set_str_variable (varname, value);
+	    free (value);
 	  }
-	  set_str_variable (varname, value);
-	  free (value);
+	  sprintf (varname, "%s:n", fieldName);
+	  set_int_variable (varname, Ny);
+	  continue;
 	}
-	sprintf (varname, "%s:n", fieldName);
-	set_int_variable (varname, Ny);
-	continue;
+	// save char-type field as a string-type vector:
+	if (!CharAsVectors) {
+	  Vector *myVector = NULL;
+	  sprintf (name, "%s", argv[i]);
+	  if ((myVector = SelectVector (name, ANYVECTOR, TRUE)) == NULL) ESCAPE ("bad vector name\n");
+	  ResetVector (myVector, OPIHI_STR, Ny);
+
+	  char *Ptr = data;
+	  for (j = 0; j < Ny; j++) {
+	    myVector[0].elements.Str[j] = strncreate (&Ptr[j*Nval], Nval);
+	    // replace instances of $ with _
+	    char *p = strchr (myVector[0].elements.Str[j], '$');
+	    while (p) { *p = '_'; p = strchr (p, '$'); }
+	  }
+	  continue;
+	}
       }
 
       // define the multifield vector names (Nval vectors x Ny elements)
+      // CharAsVectors is handled below automatically
       ALLOCATE (vec, Vector *, Nval);
       for (j = 0; j < Nval; j++) {
Index: trunk/Ohana/src/opihi/cmd.data/rotate.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/rotate.c	(revision 41164)
+++ trunk/Ohana/src/opihi/cmd.data/rotate.c	(revision 41269)
@@ -268,4 +268,5 @@
 
   out_buff = (float *)buf[0].matrix.buffer;
+
   for (j = 0; j < Ly; j++) {
     for (i = 0; i < Lx; i++, out_buff++) {
Index: trunk/Ohana/src/opihi/cmd.data/tvcolors.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/tvcolors.c	(revision 41164)
+++ trunk/Ohana/src/opihi/cmd.data/tvcolors.c	(revision 41269)
@@ -37,21 +37,8 @@
     gprint (GP_ERR, "USAGE: tvcolors (colormap) [-nan red green blue]\n");
     gprint (GP_ERR, " colormap options : greyscale, -greyscale, rainbow, heat, fullcolor, ruffcolor (also grayscale, -grayscale)\n");
-    gprint (GP_ERR, " colormap file name of the for WORD:PATH where WORD = (file,csvf,lgcy,cetf)\n");
-    gprint (GP_ERR, " lgcy:\n");
-    gprint (GP_ERR, "   the colormap file must contain 4 columns: f R B G; each line defines a color transition.\n");
-    gprint (GP_ERR, "   f: 0 - 1 defines the scale value for the transition\n");
-    gprint (GP_ERR, "   R,B,G: 0 - 1 define the value of the color at the transition point\n");
-    gprint (GP_ERR, " file:\n");
+    gprint (GP_ERR, " colormap file: if colormap name is given as file:path/to/file, the colormap is read from the file\n");
     gprint (GP_ERR, "   the colormap file must contain 4 columns: f R G B; each line defines a color transition.\n");
     gprint (GP_ERR, "   f: 0 - 1 defines the scale value for the transition\n");
     gprint (GP_ERR, "   R,G,B: 0 - 1 define the value of the color at the transition point\n");
-    gprint (GP_ERR, " csvf:\n");
-    gprint (GP_ERR, "   the colormap file must contain 4 columns: f,R,G,B separate by commas; each line defines a color transition.\n");
-    gprint (GP_ERR, "   f: 0 - 1 defines the scale value for the transition\n");
-    gprint (GP_ERR, "   R,G,B: 0 - 1 define the value of the color at the transition point\n");
-    gprint (GP_ERR, " cetf:\n");
-    gprint (GP_ERR, "   the colormap file must 256 rows contain 3 columns: R,G,B separate by commas; each line defines a color transition.\n");
-    gprint (GP_ERR, "   R,G,B: 0 - 1 define the value of the color at the transition point\n");
-    gprint (GP_ERR, "   CETF-format files can be found at : https://peterkovesi.com/projects/colourmaps\n");
     return (FALSE);
   }
Index: trunk/Ohana/src/opihi/cmd.data/write_vectors.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/write_vectors.c	(revision 41164)
+++ trunk/Ohana/src/opihi/cmd.data/write_vectors.c	(revision 41269)
@@ -154,8 +154,8 @@
   if (ADD_HEADER) {
     for (j = 0; j < Nvec; j++) {
+      if (j == 0) fprintf (f, "# ");
       if (CSV) {
 	fprintf (f, "%s,", vec[j][0].name);
       } else {
-	if (j == 0) fprintf (f, "# ");
 	fprintf (f, "%s ", vec[j][0].name);
       }
@@ -166,18 +166,17 @@
   /* default output format */
   if (format == (char *) NULL) {
+    char padChar = CSV ? ',' : ' ';
     for (i = 0; i < vec[0][0].Nelements; i++) {
       for (j = 0; j < Nvec; j++) {
-	if (vec[j][0].type == OPIHI_FLT) {
-	  if (CSV) {
-	    fprintf (f, "%.12g,", vec[j][0].elements.Flt[i]);
-	  } else {
-	    fprintf (f, "%.12g ", vec[j][0].elements.Flt[i]);
-	  }
-	} else {
-	  if (CSV) {
-	    fprintf (f, OPIHI_INT_FMT",", vec[j][0].elements.Int[i]);
-	  } else {
-	    fprintf (f, OPIHI_INT_FMT" ", vec[j][0].elements.Int[i]);
-	  }
+	switch (vec[j][0].type) {
+	  case OPIHI_FLT:
+	    fprintf (f, "%.12g%c", vec[j][0].elements.Flt[i], padChar);
+	    break;
+	  case OPIHI_INT:
+	    fprintf (f, OPIHI_INT_FMT"%c", vec[j][0].elements.Int[i], padChar);
+	    break;
+	  case OPIHI_STR:
+	    fprintf (f, "%s%c", vec[j][0].elements.Str[i], padChar);
+	    break;
 	}
       }
@@ -226,6 +225,9 @@
 	fmttype[j] = 'd';
 	break;
+      case 's':
+	fmttype[j] = 's';
+	break;
       default:
-	gprint (GP_ERR, "syntax error in format (only e,f,d,c,x allowed)\n");
+	gprint (GP_ERR, "syntax error in format (only e,f,d,c,x,s allowed)\n");
 	return (FALSE);
     }
@@ -234,4 +236,23 @@
   strcat (fmtlist[Nvec-1], p0);
   
+  // check format types against vector types:
+  for (j = 0; j < Nvec; j++) {
+    switch (vec[j][0].type) {
+      case OPIHI_FLT:
+      case OPIHI_INT:
+	if (fmttype[j] == 's') {
+	  gprint (GP_ERR, "mismatch between string format and numerical vector for %s\n", vec[j][0].name);
+	  return FALSE;
+	}
+	break;
+      case OPIHI_STR:
+	if (fmttype[j] != 's') {
+	  gprint (GP_ERR, "mismatch between numerical format and string vector for %s\n", vec[j][0].name);
+	  return FALSE;
+	}
+	break;
+    }
+  }
+
   for (i = 0; i < vec[0][0].Nelements; i++) {
     for (j = 0; j < Nvec; j++) {
@@ -249,4 +270,7 @@
 	  fprintf (f, fmtlist[j], (opihi_flt)(vec[j][0].elements.Int[i]));
 	}
+      } 
+      if (fmttype[j] == 's') {
+	fprintf (f, fmtlist[j], vec[j][0].elements.Str[i]);
       } 
     }
