function dataStructure=tdfread2struct(filename,delimiter)
%
%   TDFREAD2STRUCT(FILENAME, DELIMITER) reads a text file with a one-line
%   header, FILENAME, and puts the result into a structure using the original 
%   column names as fields. Each data column is a vector. non-letter-non-digit 
%   chars in the field namesa are converted to underscores. String fields are 
%   left as character arrays.
%   Allowable values of DELIMITER are:
%        ' ', '\t', ',', ';', '|' or their corresponding string name 
%        'space', 'tab', 'comma', 'semi', 'bar'; 'tab' is the default. 
%
%   TDFREAD2STRUCT(FILENAME) assumes delimiter is tab.
%
%   TDFREAD2STRUCT displays a dialog box for selecting a file, then reads
%   data from the file.  The field delimeter _must_ be the default tab.
%

% this version hacked by Margaret O\'Brien  2005-09-30
% puts vectors into a data structure, recognizes strings in data field, 
% replaces non-dig-non-letter chars with underscore '_' in field names 
%		Based on TDFREAD(filename) 
%   Tom Lane, 4-5-99, (modified from TBLREAD by B.A. Jones 1-4-94)
%   See also TBLREAD.
%   Copyright 1993-2002 The MathWorks, Inc. 
%   $Revision: 1.1.2.2 $  $Date: 2005/11/10 17:52:43 $



% original code from: 
% http://ccpublic-1.central.cranfield.ac.uk/2001DMSOMFRC/pr062320/Matlab/stats/tdfread.m
% changes: not using displayopt var.
% to do: reinstate the checking vnames section.
% 	1. data vectors stay strings if non-digtit strings (mainly to preserve dates) 
% 	2. cleans up non-valid variable names (to do, try genvarname())


% %%%%%%%%%%%%%%%%%% comment these lines out if you are testing out of function mode
  % set the delimiter
  if nargin < 2  
     delimiter = sprintf('\t');
  else
     switch delimiter
     case {'tab', '\t'}
        delimiter = sprintf('\t');
     case {'space',' '}
        delimiter = ' ';
     case {'comma', ','}
        delimiter = ',';
     case {'semi', ';'}
        delimiter = ';';
     case {'bar', '|'}
        delimiter = '|';
     otherwise
        delimiter = delimiter(1);
        fprintf('TDFREAD does not support the specified delimiter.\n');
        fprintf('We use %c supplied by you as the delimiter.\n',delimiter(1));
        fprintf('This may give bad results.\n');
     end
  end
  
 
  %%% open file
  F = 1;
  if nargin == 0
     filename = '';
  end
 
  if isempty(filename)
    [F,P]=uigetfile('*.*');
    filename = [P,F];
  end
 
  if (isequal(F,0)), return, end
  fid = fopen(filename,'rt');
 
  if fid == -1
    disp('Unable to open file.');
    return
  end
 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%% activate these lines when testing as non-function
% filename = 'SBCHAN_XXXHFRD001R00_20050401.40.1.txt';
% delimiter = ' ';
% fid = fopen(filename,'rt');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


lf = sprintf('\n'); % line feed is platform dependent

% now read in the data
[bigM,count] = fread(fid,Inf);
fclose(fid);
if bigM(count) ~= lf
   bigM = [bigM; lf];
end

charM = char(bigM);
charM = charM(:)';
oldM = [];
a = real(delimiter);

while ~strcmp(charM, oldM)
   oldM = charM;
   charM = strrep(charM,'  ',' ');
   charM = strrep(charM,'__','_');
   if a ~= real(sprintf('\t'))
      charM = strrep(charM,sprintf('\t\t'),sprintf('\t'));
      charM = strrep(charM,sprintf(' \t'),' ');
      charM = strrep(charM,sprintf('\t '),' ');
      charM = strrep(charM,[char(delimiter) sprintf('\t')], char(delimiter));
      charM = strrep(charM,[sprintf('\t') char(delimiter)], char(delimiter));
   else
      charM = strrep(charM,sprintf(' \t'),sprintf('\t'));
      charM = strrep(charM,sprintf('\t '),sprintf('\t'));
   end
   charM = strrep(charM,[char(delimiter) ' '], char(delimiter));
   charM = strrep(charM,[' ' char(delimiter)], char(delimiter));
end
bigM = real(charM');

% find out how many lines are there.
newlines = find(bigM == lf);

% get rid of spaces before line feed.
oldM = [];
while ~strcmp(charM, oldM)
   oldM = charM;
   b = find(bigM(newlines-1)==real(' '));
   bigM(newlines(b)-1) = [];
   newlines = find(bigM == lf);
end

% take the first line out from bigM, and put it to line1.
line1 = bigM(1:newlines(1)-1);
line1 = line1';
bigM(1:newlines(1)) = [];
newlines(1) = [];

% add a delimiter to the beginning and end of the line
if real(line1(1)) ~= a
   line1 = [delimiter, line1];
end
if real(line1(end)) ~= a
   line1 = [line1,delimiter];
end

% determine varnames
idx = find(line1==delimiter);
strlength = diff(idx)-1;
maxl = max(strlength);
nvars = length(idx)-1;
b = ' ';
varnames = repmat(b,nvars, maxl);
for k = 1:nvars;
   vn = line1(idx(k)+1:idx(k+1)-1);
   vn = strrep(vn, ' ', '_');
   varnames(k,1:strlength(k)) = vn;
end





nobs = length(newlines);

delimitidx = find(bigM == a);

% check the size validation
if length(delimitidx) ~= nobs*(nvars-1)
   error('Requires the same number of delimiters on each line.');
end
maxlength = max(diff(delimitidx));
if nvars > 1
   delimitidx = (reshape(delimitidx,nvars-1,nobs))';
end

% now we need to re-find the newlines.
newlines = find(bigM == lf);
startlines = newlines;
startlines(nobs) = [];
startlines = [0;startlines];
delimitidx = [startlines, delimitidx, newlines];
if (isempty(maxlength))
   maxlength = max(newlines - startlines);
end


for vars = 1:nvars
   x = repmat(' ', nobs,maxlength);
   for k = 1:nobs
       v = bigM(delimitidx(k,vars)+1:delimitidx(k,vars+1)-1)';                 
       x(k,1:length(v)) = v;
		      	 
   end
		 
% check the format of the first char array in each vector (x array)
% num2str called only if contents are integers or decimal points. 
% no provisions here for inconsistent fmts later in the column 
% allowable: one decimal point (sorry, no commas)
% allowable: first character is +/-
% allowable: char array = NaN
% allowable: extra wspace on the last array (inputs from dos include \r)	
length_v = length(v);
str2num_ok = 0;     % assume no
dot_cnt = 0;        % counter for '.' in each char array (x)
if( x(1,1:3) =='NaN' )
   str2num_ok = 1;         % NaNs allowed
else

    for i=1:length(v)     % isnt a NaN so look at the whole thing
        str2num_ok = 0;     % reset for each l
        character_x = x(1,i);

        if isstrprop( character_x, 'digit' )
            str2num_ok = 1;         % digits are always allowed
        else                        % some nondigs allowed, ck position, count
            switch ( i )
                case { 1 }          % postition first
                    switch ( character_x )
                        case { '+', '-' }
                            str2num_ok = 1;     % sign ok in position1
                        case { '.' }
                            str2num_ok = 1;     % decimal ok in position1
                            dot_cnt = dot_cnt + 1; % 1st, no need to count yet
                        otherwise
                            break;
                    end
                case { length_v }  % position last
                    if isstrprop (character_x, 'wspace' )   %catch CR from in files
                        str2num_ok = 1;     
                    elseif ( character_x == '.' ) 
                        dot_cnt = dot_cnt + 1;
                        if ( dot_cnt <= 1 )     % str2num allowed if only 1
                            str2num_ok = 1;
                        else
                            str2num_ok = 0;
                            break;
                        end
                    else
                        break;
                    end
                otherwise       % any other position
                    if ( character_x == '.' )
                        dot_cnt = dot_cnt + 1;
                        if ( dot_cnt <= 1 )    % str2num allowed if only 1
                            str2num_ok = 1;
                        else
                            str2num_ok = 0;
                            break;
                        end
                    else  % default for non-digit, non-special 1st,last chars
                        str2num_ok = 0;
                        break; 
                    end
                    
            end     % matches switch(position)
        end     % matches if digit               
    end % matches foreach i
end % matches if x=NaN
    
    
if ( str2num_ok == 1 )  
		y = str2num( x );  % safe to convert this string
else
		y = x;  % keep it a char array
end
%%%%%%%%%%% end check strings

     
   % reclaim x for the data vector's variable
   if (length(y) > 0)
      x = y;
   else
      x = deblank(x);
   end

   vname = deblank(varnames(vars,:));
   ok = 0;

	 % check variable names before assigning to structure
     % try genvarname? 
   if (~isvarname(vname)) 			%% vname isnt matlab-valid
			 % fix it up
	 		disp(sprintf(['replacing %s '], vname));
			% if first character not a letter, prefix the string 'struct_'
			character1=vname(1);
            if( ~isstrprop(character1, 'alpha') )
				vname=['struct_',vname];
			end
			
			% for remaining characters, only digits and alphas allowed
			% first if clause restricts to basic ascii, to remove multibyte charsq
			[foo,len_vname]=size(vname);
			for i=2:len_vname
				character=vname(i);
                                 if (ismember(character, char(32:127))  && ...    % || ...
                       isstrprop(character, 'alphanum'))  
                   % keep it
                else
					vname(i)='_';   
				end
            end   %% matches foreach character (vname)	
    disp(sprintf(['     with %s '], vname));
            
   end  %% matches vname not-ok
			
	
	
	
	%%% Put the vector into the structure:
	try
  	%% original put var in the base namespace- return a structure instead
		% assignin('base', vname, x);   % assigns the var name to vector

		% create a stucture from varnames and vectors
			dataStructure.(vname) = x;    % assign the var name to vector
			clear vname;
			ok = 1;
			catch
	end

end  %% matches foreach vnames (varnames)


       
      
      
      
      
       
       



