%PRHELP2HTML Construct HTML file from help part of PRTools routine % % S = PRHELP2HTML(COMMAND,RECREATE,HTMLDIR) % S = PRHELP2HTML(TOOLBOX,RECREATE,HTMLDIR) % % INPUT % COMMAND String with PRTools command, default: all prtools m-files % TOOLBOX Name of the toolbox to be handled, default PRTOOLS. % Toolbox should be in the bath in in this call the last % character should be a '/'. % RECREATE 0/1 flag indicating whether non-existing references % in the SEE ALSO section should be created as well % HTMLDIR String with desired directory in which the HTML % file should be stored % % OUTPUT % S HTML code written to file, empty in case of error % % DESCRIPTION % This command takes the help part of a PRTools command and creates a HTML % file in the desired sub-directory. In case it is not given, a % sub-directory is used with the same name as the (sub-)directory of % COMMAND. % % In creating HTML code the following formatting rules apply: % - NAME is used for the title and the first heading % - There are (slightly) different rules for standard sections of the % PRTools help: % INPUT, OUTPUT, DESCRIPTION, REFERENCES, EXAMPLES, SEE ALSO % - New sections are detected by their name in capitals starting at % position 1 or 2 of the line. % - The first word of the first line is skipped (assuming it is identical % to NAME). The remaining part of the line is used as heading. % - The next block of lines is assumed to be ways to call the command and % is printed as code (Courier size 3) on separate lines. % - The INPUT and OUTPUT sections are printed as two-column tables. The % first column is printed as code. % - Multiple spaces in the source are used to define column separators. % ACCIDENTAL MULTIPLE SPACES CAUSE ERRORS!!!! % - Blocks of lines in the following DESCRIPTION section are formatted as % separate paragraphs. % - Lines starting with ' - ' will start a dotted list. % - Lines following an empty line and starting with multiple spaces are % assumed to be code and printed as Courier_3. % - Lines containing sets of multiple spaces after the first words start a % two-column table. Consecutive lines starting with multiple spaces are % placed in the second column. % - Lines ending with a ':' force a break (
) in the paragraph. % - An attempt is made to detect code in text (using the Matlab convention % of upper case characters only). This is printed as Courier 2. % - Literature references in the REFERENCE section generater a break if the % line starts with a number. % - Code in the EXAMPLE section is printed as it is using Courier_2. % - Users are advised to neglect here the Matlab convention of capitals in % order to facilitate direct copying and execution. % - References are created for command names in the EXAMPLE section that % are preceded by 'See', e.g. 'See PREX_PLOTC'. % - References are created for all PRTools commands in the SEE ALSO % section. % BEFORE YOU START TO DEBUG, READ THIS % This routine was original intended to work on the prtools dir only. % Later it was somewhat changed in order to handle files in prdatasets, % prdatafiles and possibly distools and dd_tools as well. Only for % prtools the subdir structure (with the @dataset, @datafile, @mapping % sub dirs) is recognized, and only if the first parameter, COMMAND, is % empty. % % The Contents files have a special layout. It is handled by prcontent2html % in case of PRTools, but for other toolboxes it most likely doesn't work. % % The formatting rules of the PRTools help are strict. Don't try to relax % them in the below code, but change the help-text if you are not satisfied % with the result. Especially avoid ' ' (double spaces) where they are not % needed as the conversion jumps into a table-mode as soon as they are % encountered. % % Bob Duin, April 2011 function out = prhelp2html(name,recreate,htmldir) if nargin < 3, htmldir = cd; end if nargin < 2 | isempty(recreate), recreate = 0; end if nargin < 1 | isempty(name) % default is prtools dirs = {'ldc','dataset','datafile','mapping'}; run_all_files(mfilename,dirs,htmldir); s = prcontent2html('prtools',[],htmldir); if nargout > 0 out = s; end return; else if strcmp(name(end),'/') & exist(name(1:end-1),'dir') == 7 name = name(1:end-1); dirs = {fullfile(name,'Contents.m')}; run_all_files(mfilename,dirs,htmldir); s = prcontent2html(name,[],htmldir); % does not work usually if nargout > 0 out = s; end return end end file = which(name); if isempty(file) disp([' -----> ' name ' not found']); out = []; return end %[pp,name] = fileparts(file); if isempty(htmldir) [xx,htmldir] = fileparts(fileparts(file)); end % if isempty(strmatch(subdir,char('prtools','@dataset','@datafile','@mapping'),'exact')) % % disp([name ' Not PRTools']) % out = []; % return % end disp(file) t = gethf(file); % help part t = strrep(t,char([10 13]),char(10)); t = strrep(t,char([13 10]),char(10)); t = strrep(t,char(13),char(10)); t = strrep(t,char(9),char([32 32])); n = length(strfind(t,10)); s = ['' content_manual '' name '' newline]; s = [s '

' upper(name) '

' newline]; title = listn(t,1); [qq,title] = strtok(title); % get rid of first word, probably name s = [s '

' title '

' newline]; s = [s '

' newline]; liston = false; previous_empty = false; coding = false; cellopen = false; tabstate = false; if strfind(lower(title),'info') state = 'text'; else state = 'start'; end nextlinespace = htmlspace; for j=2:n % do for all lines newlinespace = nextlinespace; nextlinespace = htmlspace; r = listn(t,j); u = cleanstr(r); % if strfind(r,'supplied') % disp(r) % end [tok,posttok] = strtok(u); single = isempty(strtok(posttok)); emptyline = isempty(tok); if length(r) < 2, startspace = false; tabstartspace = false; else startspace = strcmp(r(1:2),' '); if length(r) < 4 || ~tabstate tabstartspace = false; else tabstartspace = strcmp(r(1:4),' '); colpos1 = find(r ~= ' ',1,'first'); end if tabstartspace startspace = false; end end uppertoken = isupper(tok); upperline = isupper(u); functioncall = ~isempty(strfind(lower(r),name)); input = strcmp(tok,'INPUT'); output = strcmp(tok,'OUTPUT'); listline = strcmp(tok,'-'); description = strcmp(tok,'DESCRIPTION'); example = strcmp(tok,'EXAMPLE') | strcmp(tok,'EXAMPLES'); reference = strcmp(tok,'REFERENCE') | strcmp(tok,'REFERENCES'); seealso = strcmpi(tok,'SEE') & strcmpi(strtok(posttok),'ALSO'); inputstate = strcmp(state,'input'); outputstate = strcmp(state,'output'); tabstate = strcmp(state,'tab'); startstate = strcmp(state,'start'); commandstate = strcmp(state,'command'); textstate = strcmp(state,'text'); examplestate = strcmp(state,'examp'); seealsostate = strcmp(state,'seealso'); refstate = strcmp(state,'reference'); iotabstate = inputstate | outputstate; ntabs = regexp(strtrim(r),' *','start'); tab = length(ntabs>1) | (length(ntabs)==1 && ntabs(1)>1); if seealso % get rid of also [qq,posttok] = strtok(posttok); single = isempty(strtok(posttok)); end if previous_empty && ~startspace && ~tabstartspace && ~tab && tabstate if cellopen s = closecell(s); cellopen = false; end s = endtable(s); s = [s '

' newline '

']; state = oldstate; end if emptyline % start new paragraph if liston, s = [s '']; liston = false; end if iotabstate s = endtable(s); state = 'text'; else s = [s '

' newline '

']; %#ok end if ~examplestate coding = false; end elseif (startspace && ((functioncall && upperline) || commandstate)) || startstate % command %n = findstr(u,'='); % align = %n = min(n,17); % but dont exeggarate n = find(r~=' ',1,'first'); s = [s code(u,n,3) '
' newline]; state = 'command'; elseif input && single % input if commandstate || textstate % start table s = [s '

' newline]; % new paragraph s = [s '']; state = 'input'; end elseif output && single if inputstate s = endtable(s); % end inputtable end if inputstate || commandstate || textstate % start table s = [s '

']; % new paragraph s = [s '

Input
']; end state = 'output'; elseif iotabstate % input/output table if uppertoken % next input/output parameter s = [s '']; [f0,f1] = regexp(posttok,'^ *[:-] *'); if ~isempty(f0) posttok = posttok(f1+1:end); end s = [s '']; %LISTN List lines specified by their line number % % t = listn(r,n) % Get the lines in r given by the line numbers in n. function t = listn(r,n) k = [0,find(r==newline)]; t = []; for j = n if j < length(k) t = [t,r(k(j)+1:k(j+1))]; end end return function run_all_files(command,dirs,subdir) %dirs = {'ldc','dataset','datafile','mapping'}; for n=1:length(dirs) prtools_dir = fileparts(which(dirs{n})); [qq,prtools_dirname] = fileparts(prtools_dir); % get rid of root ff = dirnames(prtools_dir); for j=1:length(ff) [qq,name] = fileparts(ff{j}); if n==1 feval(command,name,[],fullfile(subdir,prtools_dirname)); % prtools main commands else feval(command,fullfile(prtools_dirname,name),[],fullfile(subdir,prtools_dirname)); % subdir commands end end end function files = dirnames(direct) % get all m-files in dir allnames = dir(fullfile(direct,'*.m')); files = char(allnames(:).name); files(strmatch('Contents.m',files),:) = []; files(strmatch('Readme.m',files),:) = []; files = cellstr(files); function s = gethf(file) %GETHF Create heading file from m-file % % s = gethf(file) % % The heading of the given m-file consisting of all starting % lines % is isolated and returned in s. % % gethf(dir) % % All headings of the files in dir are merged into a file named headings.doc. % Default dir is cd. % % Use mergeprt for restoring if nargin == 0 gethf(cd); end if isdir(file) files = dir(file); docfile = ['headings.doc']; m = size(files,1); for i = 1:m if (~files(i,:).isdir) & (files(i,:).name(end-1:end) == '.m') name = files(i,:).name; s = gethf(name); s = ['##1' name(1:end-2) newline s newline '##2' newline]; %disp(s) appendf(docfile,s); end end else %disp(file) [s,ns] = readf(file); p = grep(s,'%'); if isempty(p) % no comments found s = []; return end p = [p p(end)+10]; % trick I = find(p - [0,p(1:length(p)-1)] ~= 1); if p(1) == 1 & isempty(I), I = length(p) + 1; end % if length(I) > 0 & I(1) > 1 if length(I) > 0 if I(1) == 1 I(1) = []; end n = I(1) - 1; s = listn(s,p(1):n+p(1)-1); s = strrep(s,[newline '%'],newline); %s = strrep(s,[newline ' '],newline); %s = strrep(s,[newline newline],'&*&'); %s = strrep(s,[newline ' '],'*&* '); %s = strrep(s,newline,' '); %s = strrep(s,'&*&',[newline newline]); %s = strrep(s,'*&*',newline); s = s(2:end); else s = ''; end end function [r,n] = readf(file,newline) %READF Readfile % % [r,n] = readf(file,newline) % Reads file into string r. The number of lines % is returned in n. if nargin < 2, newline = 13; end fid = fopen(deblank(file),'r'); if fid < 0 error(['Cann''t open ' file]) end r = fscanf(fid,'%c'); fclose(fid); n = length(find(r==newline)); if r(length(r)) ~= newline, n = n + 1; end return function writf(file,r) %WRITF Write file % % writf(file,r) % Write file from string r fid = fopen(file,'w'); if fid < 0 error(['Cannot open file ' file]) end fprintf(fid,'%c',r); fclose(fid); return function [k,z] = grep(r,s) %GREP Get line specific lines % % [k,n] = grep(r,s) % Get the numbers of all lines in the set of lines r % that contain s. % n is the total number of lines. n = [0,find(r==newline)]; m = findstr(r,s); [i,j] = sort([n,m]);; q = [0,j(1:length(j)-1)]-j; k = j(find(q>0))-1; z = length(n)-1; % # of lines return function t = content_manual t = ['
Output
' makecode(tok,1) '' findmakecode(posttok)]; else % continuation of description s = [s htmlspace findmakecode(u)]; end elseif (tab || tabstate) ... && ~examplestate && ~startspace && ~tabstartspace % arbitrary table if ~tabstate % start table if liston, s = [s '']; liston = false; end s = [s '

']; % new paragraph s = [s '']; % get rid of : [f0,f1] = regexp(posttok,'^ *: *'); if ~isempty(f0) posttok = posttok(f1+1:end); end colpos0 = findstr(cleanstr(posttok),r); % store starting pos 2nd cell % second cell s = [s '
' makecode(tok,1) '']; [tok2,posttok2] = strtok(posttok); if strcmp(tok2,'-') % possible start of list s = [s '
  • ' findmakecode(posttok2)]; liston = true; else s = [s findmakecode(posttok)]; liston = false; end cellopen = true; elseif startspace && tab && ~textstate if liston, s = [s '
']; liston = 0; end s = [s htmlspace findmakecode(u)]; elseif description && single s = endtable(s,tab); s = [s '

Description

' newline]; state = 'text'; elseif reference && single s = endtable(s,tab); s = [s '

Reference(s)

' newline]; nref = 0; state = 'reference'; elseif example && single s = endtable(s,tab); s = [s '

Example(s)

' newline]; state = 'examp'; % elseif seealso && single % s = endtable(s,tab); % s = [s '

See also

' newline]; % state = 'seealso'; elseif seealso s = endtable(s,tab); s = [s '

See also

' newline]; state = 'seealso'; if ~single s = [s commandrefs(posttok,recreate,htmldir)]; end else % undefined lines if examplestate if length(u) > 3 && strcmpi(u(1:4),'see ') s = [s '

' commandrefs(u(5:end),recreate,fileparts(htmldir)) '

']; else s = [s strrep(code(strrep(r,' ','#$!'),0,3),'#$!',' ') '
']; % s = [s code(r) '
']; end elseif refstate if abs(u(1)>=48) && abs(u(1)<=57) && nref > 0 s = [s '
' u]; else s = [s htmlspace u]; nref = 1; end elseif seealsostate if listline s = [s '' findmakecode(u(3:end)) '
']; else s = [s commandrefs(u,recreate,htmldir)]; end elseif tabstartspace && tabstate && (colpos1 > colpos0) ... && (previous_empty || coding) % start code in table s = [s strrep(code(strrep(r(colpos0:end),' ','#$!'),0,3),'#$!',' ') '
']; coding = true; elseif startspace && ~tabstate && ~liston ... && (previous_empty || coding) % code line s = [s strrep(code(strrep(r,' ','#$!'),2,3),'#$!',' ') '
']; nextlinespace = ''; coding = true; elseif listline if ~liston s = [s '

    ']; liston = true; end if u(end) == ':' s = [s '
  • ' findmakecode(u(3:end-1)) '
    ']; nextlinespace = ''; else s = [s '
  • ' findmakecode(u(3:end))]; end % elseif tabstate && ~startspace && ~tabstartspace % end of table % s = endtable(s); % state = oldstate; % s = [s findmakecode(u)]; elseif tabstate % next line in table, store starting position colpos0 = colpos1; s = [s newlinespace findmakecode(cleanstr(u))]; else % just a line if u(end) == ':' s = [s newlinespace findmakecode(cleanstr(u(1:end-1))) '
    ']; nextlinespace = ''; else s = [s newlinespace findmakecode(cleanstr(u))]; end % s = [s newlinespace findmakecode(cleanstr(u))]; end end if emptyline previous_empty = true; else previous_empty = false; end end if cellopen s = closecell(s); end if tabstate s = endtable(s); end s = strrep(s,'

     ','

    '); s = strrep(s,'  ',' '); s = strrep(s,['

    ' newline ' '],'

    '); s = [s '

    ' content_manual '']; [qq,name] = fileparts(name); % allows for names like dataset/show % if exist(fullfile(htmldir,name),'file') == 2 % htmlname = fullfile(htmldir,name); % else % %htmlname = [tok '.html']; % file = which(name); % pp = fileparts(file); % [qq,subdir] = fileparts(pp); % htmldir = fullfile(fileparts(htmldir),subdir); % htmlname = fullfile(htmldir,name); % end if exist([htmldir],'file') ~= 7 mkdir(htmldir); end writf([fullfile(htmldir,name) '.html'],s); disp([int2str(recreate) ' ' name ' html created']) if nargout > 0 out = s; end return function i = isupper(s) % true if s doesnot change by upper i = strcmp(s,upper(s)); return function out = code(s,n,fsize) %convert s to Courier, add n spaces in front, fontsize fsize if nargin < 3, fsize = 2; end if nargin < 2, n = 0; end out = ['' htmlspace(n) s '']; return function out = makecode(s,n,fsize) %convert any consequetive set of uppers and make them Courier size fsize, % add n spaces in front if strmatch(s(end),char(',','.')) send = s(end); s(end) = []; elseif length(s) > 1 && ~isempty(strmatch(s(end-1:end),char(', ','. '))) send = s(end-1:end); s(end-1:end) = []; else send = []; end if nargin < 3, fsize = 2; end if nargin < 2, n = 0; end out = []; if isupper(s) %out = code(lower(s),n); out = code(s,n,fsize); else while ~isempty(s) [t,s] = strtok(s); if isupper(t) %t = code(lower(t)); t = code(t,n,fsize); end out = [out ' ' t]; end end out = [out send]; return function s = cleanstr(s) V = char([9 10 11 12 13 32]); for n=1:length(s) if all(V~=s(n)) break; end end s = s(n:end); for n=length(s):-1:1 if all(V~=s(n)) break end end s = s(1:n); return function s = endtable(s,tab) if strcmp(s(end-7:end),char([60 47 112 62 10 60 112 62])) s(end-7:end) = []; end if strcmp(s(end-6:end),char([60 47 112 62 60 112 62])) s(end-7:end) = []; end if nargin < 2 || tab % don't do this for tab = 0 s = [s '
' newline]; % end table end function s = commandrefs(r,recreate,htmldir) if nargin < 3, htmldir = cd; end if nargin < 2 | isempty(recreate), recreate = 0; end s = []; r_debug = r; while ~isempty(r) && isempty(regexp(r,'^[ .,]*$', 'once' )) [tok,r] = strtok(r,' .,'); tok = lower(tok); htmlname = [tok '.html']; file = which(tok); pp = fileparts(file); [qq,subdir] = fileparts(pp); % htmlname = fullfile(subdir,htmlname); htmlfullname1 = fullfile(htmldir,htmlname); htmlfullname2 = fullfile(fullfile(fileparts(htmldir),subdir),htmlname); if exist(htmlfullname1,'file') == 2 % check whether command is in htmldir s = [s '' tok ', ']; elseif exist(htmlfullname2,'file') == 2 % exists elsewhere? s = [s '' tok ', ']; elseif isempty(tok) || ~isempty(regexp(tok,'^ *', 'once' )) ; elseif recreate tt = prhelp2html(tok); % don't iterate further! if ~isempty(tt) s = [s '' tok ', ']; else % disp([r_debug ' --> ' tok ]) s = [s tok ', ']; end else s = [s tok ', ']; end end if ~isempty(s) % s(end-1:end) = []; s = code(s,0,3); end s = strrep(s,'\','/'); % avoid \ in html addresses return function s = htmlspace(n) if nargin < 1, n=1; end if n > 0 s = repmat(' ',1,n); else s = []; end return function s = findmakecode(r) % find pieces of code (capitals only) and convert them to lower Courier r = strrep(r,'. A ','. aA '); % prevent conversion of A at the start of a sentence r = [' ' r ' ']; % ending space may be helpful r = strrep(r,'NaN',code('NaN')); [f0,f1] = regexp(r,'[ ,(\[]+[A-Z0123456789=<>(){},.''''*+\\/;:\[\]_ ]+[ .,-]'); %[f0,f1,toks] = regexp(r,'[ ,(]+[A-Z0123456789=<>(){},*+\\/;:\[\]_ ]+[ .,-]'); if ~isempty(f0) if f0(1) > 1 % first part no code s = r(1:f0(1)-1); else s = []; end for j=1:length(f0) % all code parts s = [s makecode(r(f0(j):f1(j)))]; if j < length(f0) % between code parts s = [s r(f1(j)+1:f0(j+1)-1)]; end end if f1(end) < length(r) % last part no code s = [s r(f1(end)+1:end)]; end else s = r; end if s(end) == ' ', s(end) = []; end % remove ending space s = strrep(s,'. aA ','. A '); % convert prevention back function s = closecell(s) if strcmp(s(end-7:end),char([60 47 112 62 10 60 112 62])) s(end-7:end) = []; elseif strcmp(s(end-6:end),char([60 47 112 62 60 112 62])) s(end-7:end) = []; end s = [s '

'... '
contents' ... '

manual

']; return