function [ fields, values, header_length, nfields ] = nistread(fid)
% [ fields, values, header_length, nfields ] = nistread(fid)
%
% Read the header for a NIST-type file.
% It is up to the user to interpret the returned fields, 
% and to read the actual data from the file.
%
% fid - file identifier
% fields - cell array of strings containing field names
% values - cell array of strings containing values
% 
% If cell types are specified, values are of either numeric or char type,
% depending on whether the type was '-s' or not.
% If cell types are not specified, all values are assumed of type string.
%
% VECTOR-VALUED FIELDS:
%
% If a field name contains the string '___' followed by a number,
% the part of the name which precedes '___' is interpreted as the name
% of a vector-valued field, and the part which follows '___' is interpreted
% as a vector index.
%
% DIAGNOSTICS:
%
% This routine starts by attempting
% fscanf(fid, 'NIST_1A\n%7d\n');
% If this fails, the following things happen:
%  1 - all returned cell arrays have zero length, and header_length=0
%  2 - only as many characters are read from fid as are necessary to
%      determine that it fails the format test.  Thus, for example,
%      a '.mat' file starting with the string 'MATLAB' will be left untouched.
%
%

% Initialize fields, values, nfields
fields = {};
values = {};
nfields = {};

% Try to read the header_length
header_length = fscanf(fid, 'NIST_1A\n%d\n');
if length(header_length)==0, 
  return;
end;

% Read the rest of the header; assume top header was 16 characters
str = char(fread(fid, max(0,header_length-16), 'char'))';

% Parse the rest of the header
nfields = 0;
while length(str) > 0,
  
  % Attempt to read the next line, and see if it's end_head
  % Assume that lines are separated by LF (ASCII 10), not the machine-local line end char
  [ line, str ] = strtok(str, 10);
  if strmatch('end_head', line),
    return;
  end;
  
  % Attempt to read field name and type from the line
  nfields = nfields+1;
  [ fields{nfields}, line ] = strtok(line);
  [ type, line ] = strtok(line);

  % Parse the value, based on specified type
  if strmatch('-', type),
    if strmatch('-s', type),
      % If '-s', strip off the first space or tab, and return the rest
      values{nfields} = char(line(2:length(line)));
    
    else,
      % If any other specified type, try to convert to a numeric vector
      values{nfields} = [];
      while length(line)>0,
	[ nextent, line ] = strtok(line);
	values{nfields} = [ values{nfields} str2num(nextent) ];
      end
    end;
  else,
    % If no '-', then assume there is no specified type
    values{nfields} = [ type line ];
  end;

  % Check the fieldname to see if this might be a vector field
  where=findstr(fields{nfields}, '___');
  if length(where)>0,
    % If triple-underscore is found, try to interpret the field as a name plus a vector index
    truefield = fields{nfields}(1:(where-1));
    vecindex = str2num(fields{nfields}((where+3):length(fields{nfields})));
    if length(vecindex)>0,
      % If a valid vector index is found, then see if this field has been previously identified 
      fieldindex = strmatch(truefield, fields, 'exact');
      if length(fieldindex)>0, 
	% If the field already exists, add this entry to it, and delete this separate entry
	values{fieldindex}(vecindex) = values{nfields};
	values = { values{1:(nfields-1)} };
	fields = { fields{1:(nfields-1)} };
	nfields=nfields-1;
      else,
	% If the field does not already exist, create it
	fields{nfields} = truefield;
	values{nfields} = [ zeros(1,vecindex-1) values{nfields} ];
      end
    end
  end
  
  
end;  

  
  
  
  


