highlight.m
0001 function highlight(mfile,options,outfile)
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059 error(nargchk(1,3,nargin));
0060
0061 opt = struct('type', 'html', ...
0062 'tabs', 4, ...
0063 'linenb', 1, ...
0064 'indent', 0);
0065 if nargin >= 2
0066 if isstruct(options)
0067 names = fieldnames(options);
0068 for i=1:length(names)
0069 opt = setfield(opt,names{i},getfield(options,names{i}));
0070 end
0071 elseif ischar(options)
0072 opt.type = options;
0073 else
0074 error('Bad input argument.');
0075 end
0076 end
0077 if strcmp(lower(opt.type),'latex'), opt.type = 'tex'; end
0078 if strcmp(lower(opt.type),'xml'), opt.linenb = 1; end
0079
0080
0081 if nargin < 3
0082 [pathstr, name, ext] = fileparts(mfile);
0083 outfile = fullfile(pathstr, [name, '.' lower(opt.type)]);
0084 end
0085
0086
0087 if ischar(outfile)
0088 outfid = fopen(outfile,'wt');
0089 if outfid == -1
0090 error(sprintf('Cannot open ',outfile));
0091 end
0092 feval([lower(opt.type) '_file_start'],outfid,mfile);
0093
0094 else
0095 outfid = outfile;
0096 end
0097
0098
0099 mfid = fopen(mfile,'rt');
0100 if mfid == -1
0101 error(sprintf('Cannot open ',mfile));
0102 end
0103
0104
0105 write_highlighted_code(mfid,outfid,opt)
0106
0107
0108 fclose(mfid);
0109 if ischar(outfile),
0110 feval([lower(opt.type) '_file_end'],outfid);
0111 fclose(outfid);
0112 end
0113
0114
0115 function write_highlighted_code(mfid,outfid,opt)
0116 matlabKeywords = getMatlabKeywords;
0117 mKeySort = getMatlabKeywordsSorted;
0118 out_format = feval([lower(opt.type) '_format']);
0119 strtok_delim = sprintf(' \t\n\r(){}[]<>+-*~!|\\@&/.,:;="''%');
0120
0121 fprintf(outfid,out_format.pre_start);
0122 nbline = 1;
0123 nbblanks = 0;
0124 flagnextline = 0;
0125 while 1
0126 tline = fgetl(mfid);
0127 if ~ischar(tline), break, end
0128 tline = feval([lower(opt.type) '_special_char'],horztab(tline,opt.tabs));
0129
0130 if opt.linenb
0131 fprintf(outfid,out_format.nb_line,nbline);
0132 nbline = nbline + 1;
0133 end
0134
0135 if opt.indent
0136 tline = fliplr(deblank(fliplr(tline)));
0137 end
0138 nbblanks = nbblanks + flagnextline;
0139 flagnextline = 0;
0140
0141 splitc = splitcode(tline);
0142 newline = '';
0143 for i=1:length(splitc)
0144 if isempty(splitc{i})
0145 elseif splitc{i}(1) == ''''
0146 newline = [newline sprintf(out_format.string,splitc{i})];
0147 elseif splitc{i}(1) == '%'
0148 newline = [newline sprintf(out_format.comment,splitc{i})];
0149 elseif ~isempty(strmatch('...',splitc{i}))
0150 newline = [newline sprintf(out_format.cont,'...')];
0151 if ~isempty(splitc{i}(4:end))
0152 newline = [newline sprintf(out_format.comment,splitc{i}(4:end))];
0153 end
0154 else
0155
0156 r = splitc{i};
0157 stringcode = '';
0158 while 1
0159 [t,r,q] = strtok(r,strtok_delim);
0160 stringcode = [stringcode q];
0161 if isempty(t), break, end;
0162 isNextIncr = any(strcmp(t,mKeySort.nextincr));
0163 isNextIncr2 = any(strcmp(t,mKeySort.nextincr2));
0164 isCurrDecr = any(strcmp(t,mKeySort.currdecr));
0165 isNextDecr = any(strcmp(t,mKeySort.nextdecr));
0166 isOther = any(strcmp(t,mKeySort.other));
0167 if isNextDecr
0168
0169 rr = fliplr(deblank(fliplr(r)));
0170 icomma = strmatch(',',rr);
0171 isemicolon = strmatch(';',rr);
0172 if ~(isempty(rr) | ~isempty([icomma isemicolon]))
0173 isNextDecr = 0;
0174 else
0175 nbblanks = nbblanks - 1;
0176 flagnextline = flagnextline + 1;
0177 end
0178
0179 end
0180 if isNextIncr, flagnextline = flagnextline + 1; end
0181 if isNextIncr2, flagnextline = flagnextline + 2; end
0182 if isNextDecr, flagnextline = flagnextline - 1; end
0183 if isCurrDecr, nbblanks = nbblanks - 1; end
0184
0185 if isNextIncr | isNextIncr2 |isCurrDecr | isNextDecr | isOther
0186 if ~isempty(stringcode)
0187 newline = [newline sprintf(out_format.code,stringcode)];
0188 stringcode = '';
0189 end
0190 newline = [newline sprintf(out_format.keyword,t)];
0191 else
0192 stringcode = [stringcode t];
0193 end
0194 end
0195 if ~isempty(stringcode)
0196 newline = [newline sprintf(out_format.code,stringcode)];
0197 end
0198 end
0199 end
0200 if ~opt.indent, nbblanks = 0; end
0201
0202 fprintf(outfid,out_format.line,[blanks(nbblanks*opt.tabs) newline]);
0203 end
0204 fprintf(outfid,out_format.pre_end);
0205
0206
0207
0208
0209 function html_file_start(fid,mfile)
0210 fprintf(fid,[ ...
0211 '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"\n' ...
0212 '\t"http://www.w3.org/TR/REC-html40/loose.dtd">\n' ...
0213 '<html>\n<head>\n<title>%s</title>\n' ...
0214 '<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">\n' ...
0215 '<meta name="generator" content="highlight.m © 2003 Guillaume Flandin">\n' ...
0216 '<style type="text/css">\n' ...
0217 ' .comment {color: #228B22;}\n' ...
0218 ' .string {color: #B20000;}\n' ...
0219 ' .keyword, .cont {color: #0000FF;}\n' ...
0220 ' .cont {text-decoration: underline;}\n' ...
0221 ' .code {color: #000000;}\n' ...
0222 '</style>\n' ...
0223 '</head>\n<body>\n'],mfile);
0224
0225
0226 function html_file_end(fid)
0227 fprintf(fid,'\n</body>\n</html>');
0228
0229
0230 function format = html_format
0231 format.string = '<span class="string">%s</span>';
0232 format.comment = '<span class="comment">%s</span>';
0233 format.code = '%s';
0234 format.keyword = '<span class="keyword">%s</span>';
0235 format.cont = '<span class="cont">%s</span>';
0236 format.pre_start = '<pre class="mcode">';
0237 format.pre_end = '</pre>\n';
0238 format.nb_line = '%04d ';
0239 format.line = '%s\n';
0240
0241
0242 function str = html_special_char(str)
0243
0244 str = strrep(str,'&','&');
0245 str = strrep(str,'<','<');
0246 str = strrep(str,'>','>');
0247 str = strrep(str,'"','"');
0248
0249
0250
0251
0252 function xhtml_file_start(fid,mfile)
0253 fprintf(fid,[ ...
0254 '<?xml version="1.0"?>\n' ...
0255 '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" ' ...
0256 '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\n' ...
0257 '<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">\n' ...
0258 '<head>\n<title>%s</title>\n' ...
0259 '<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />\n' ...
0260 '<meta name="generator" content="highlight.m © 2003 Guillaume Flandin" />\n' ...
0261 '<style type="text/css">\n' ...
0262 ' .comment {color: #228B22;}\n' ...
0263 ' .string {color: #B20000;}\n' ...
0264 ' .keyword, .cont {color: #0000FF;}\n' ...
0265 ' .cont {text-decoration: underline;}\n' ...
0266 ' .code {color: #000000;}\n' ...
0267 '</style>\n' ...
0268 '</head>\n<body>\n'],mfile);
0269
0270
0271 function xhtml_file_end(fid)
0272 fprintf(fid,'\n</body>\n</html>');
0273
0274
0275 function format = xhtml_format
0276 format.string = '<span class="string">%s</span>';
0277 format.comment = '<span class="comment">%s</span>';
0278 format.code = '%s';
0279 format.keyword = '<span class="keyword">%s</span>';
0280 format.cont = '<span class="cont">%s</span>';
0281 format.pre_start = '<pre class="mcode">';
0282 format.pre_end = '</pre>\n';
0283 format.nb_line = '%04d ';
0284 format.line = '%s\n';
0285
0286
0287 function str = xhtml_special_char(str)
0288
0289 str = strrep(str,'&','&');
0290 str = strrep(str,'<','<');
0291 str = strrep(str,'>','>');
0292 str = strrep(str,'"','"');
0293
0294
0295
0296
0297
0298 function xml_file_start(fid,mfile)
0299 fprintf(fid,[ ...
0300 '<?xml version="1.0" encoding="iso-8859-1" ?>\n' ...
0301 '<!DOCTYPE mfile SYSTEM "matlab.dtd">\n' ...
0302 '<mfile name="%s">\n'],mfile);
0303
0304
0305 function xml_file_end(fid)
0306 fprintf(fid,'</mfile>');
0307
0308
0309 function format = xml_format
0310 format.string = '<string>%s</string>';
0311 format.comment = '<comment>%s</comment>';
0312 format.code = '%s';
0313 format.keyword = '<keyword>%s</keyword>';
0314 format.cont = '<cont>%s</cont>';
0315 format.pre_start = '';
0316 format.pre_end = '';
0317 format.nb_line = '<line nb="%04d ">';
0318 format.line = '%s</line>\n';
0319
0320
0321 function str = xml_special_char(str)
0322
0323 str = strrep(str,'&','&');
0324 str = strrep(str,'<','<');
0325 str = strrep(str,'>','>');
0326 str = strrep(str,'"','"');
0327
0328
0329
0330
0331
0332 function tex_file_start(fid,mfile)
0333 fprintf(fid,['\\documentclass[a4paper,10pt]{article}\n' ...
0334 ' \\usepackage{alltt}\n' ...
0335 ' \\usepackage{color}\n' ...
0336 ' \\usepackage{fullpage}\n' ...
0337 ' \\definecolor{string}{rgb}{0.7,0.0,0.0}\n' ...
0338 ' \\definecolor{comment}{rgb}{0.13,0.54,0.13}\n' ...
0339 ' \\definecolor{keyword}{rgb}{0.0,0.0,1.0}\n' ...
0340 ' \\title{%s}\n' ...
0341 ' \\author{\\textsc{Matlab}, The Mathworks, Inc.}\n' ...
0342 '\\begin{document}\n' ...
0343 '\\maketitle\n'],mfile);
0344
0345
0346 function tex_file_end(fid)
0347 fprintf(fid,'\\end{document}');
0348
0349
0350 function format = tex_format
0351 format.string = '\\textcolor{string}{%s}';
0352 format.comment = 'textcolor{comment}{%s}';
0353 format.code = '%s';
0354 format.keyword = '\\textcolor{keyword}{%s}';
0355 format.cont = '\\textcolor{keyword}{\\underline{%s}}';
0356 format.pre_start = '\\begin{alltt}\n';
0357 format.pre_end = '\\end{alltt}\n';
0358 format.nb_line = '%04d ';
0359 format.line = '%s\n';
0360
0361
0362 function str = tex_special_char(str)
0363
0364 str = strrep(str,'\','\(\backslash\)');
0365 str = strrep(str,'#','\#');
0366 str = strrep(str,'$','\$');
0367 str = strrep(str,'%','\%');
0368 str = strrep(str,'&','\&');
0369 str = strrep(str,'_','\_');
0370 str = strrep(str,'{','\{');
0371 str = strrep(str,'}','\}');
0372 str = strrep(str,'^','\^{}');
0373 str = strrep(str,'~','\~{}');
0374
0375
0376
0377
0378 function rtf_file_start(fid,mfile)
0379 fprintf(fid,['{\\rtf1\\ansi\n\n' ...
0380 '{\\fonttbl{\\f0\\fmodern\\fcharset0\\fprq1 Courier New;}}\n\n' ...
0381 '{\\colortbl;\n' ...
0382 '\\red0\\green0\\blue0;\n' ...
0383 '\\red0\\green0\\blue255;\n' ...
0384 '\\red0\\green255\\blue255;\n' ...
0385 '\\red0\\green255\\blue0;\n' ...
0386 '\\red255\\green0\\blue255;\n' ...
0387 '\\red255\\green0\\blue0;}\n\n' ...
0388 '{\\info{\\title %s}\n' ...
0389 '{\\author HighLight.m Copyright 2003}\n' ...
0390 '{\\creatim\\yr%s\\mo%s\\dy%s}' ...
0391 '{\\*\\manager Guillaume Flandin}\n' ...
0394 'matlab/highlight/}}\n\n'],mfile,...
0395 datestr(date,'yyyy'),datestr(date,'mm'),datestr(date,'dd'));
0396
0397
0398 function rtf_file_end(fid)
0399 fprintf(fid,'}');
0400
0401
0402 function format = rtf_format
0403 format.string = '{\\cf6 %s}';
0404 format.comment = '{\\cf4 %s}';
0405 format.code = '{%s}';
0406 format.keyword = '{\\cf2 %s}';
0407 format.cont = '{\\cf2 %s}';
0408 format.pre_start = '{\\f0\\fs16{';
0409 format.pre_end = '}}';
0410 format.nb_line = '{%04d }';
0411 format.line = '%s\n\\par ';
0412
0413
0414 function str = rtf_special_char(str)
0415 str = strrep(str,'\','\\');
0416 str = strrep(str,'{','\{');
0417 str = strrep(str,'}','\}');
0418
0419
0420
0421
0422 function matlabKeywords = getMatlabKeywords
0423
0424 matlabKeywords = {'break', 'case', 'catch', 'continue', 'elseif', 'else',...
0425 'end', 'for', 'function', 'global', 'if', 'otherwise', ...
0426 'persistent', 'return', 'switch', 'try', 'while'};
0427
0428
0429 function mKeySort = getMatlabKeywordsSorted
0430 mKeySort.nextincr = {'for', 'while', 'if', 'else', 'elseif', ...
0431 'case', 'otherwise', 'try', 'catch'};
0432 mKeySort.nextincr2 = {'switch'};
0433 mKeySort.currdecr = {'else', 'elseif', 'case', 'otherwise', 'catch'};
0434 mKeySort.nextdecr = {'end'};
0435 mKeySort.other = {'break', 'continue', 'function', 'global', ...
0436 'persistent', 'return'};
0437
0438
0439
0440
0441 function str = horztab(str,n)
0442
0443
0444
0445 if n > 0
0446 str = strrep(str,sprintf('\t'),blanks(n));
0447 end
0448
0449
0450
0451
0452 function splitc = splitcode(code)
0453
0454
0455
0456 iquote = findstr(code,'''');
0457 quotetransp = [double('_''.)}]') ...
0458 double('A'):double('Z') ...
0459 double('0'):double('9') ...
0460 double('a'):double('z')];
0461 flagstring = 0;
0462 flagdoublequote = 0;
0463 jquote = [];
0464 for i=1:length(iquote)
0465 if ~flagstring
0466 if iquote(i) > 1 & any(quotetransp == double(code(iquote(i)-1)))
0467
0468 else
0469
0470 jquote(size(jquote,1)+1,:) = [iquote(i) length(code)];
0471 flagstring = 1;
0472 end
0473 else
0474 if flagdoublequote | ...
0475 (iquote(i) < length(code) & strcmp(code(iquote(i)+1),''''))
0476
0477 flagdoublequote = ~flagdoublequote;
0478 else
0479
0480 jquote(size(jquote,1),2) = iquote(i);
0481 flagstring = 0;
0482 end
0483 end
0484 end
0485
0486
0487 ipercent = findstr(code,'%');
0488 jpercent = [];
0489 for i=1:length(ipercent)
0490 if isempty(jquote) | ...
0491 ~any((ipercent(i) > jquote(:,1)) & (ipercent(i) < jquote(:,2)))
0492 jpercent = [ipercent(i) length(code)];
0493 break;
0494 end
0495 end
0496
0497
0498 icont = findstr(code,'...');
0499 for i=1:length(icont)
0500 if (isempty(jquote) | ...
0501 ~any((icont(i) > jquote(:,1)) & (icont(i) < jquote(:,2)))) & ...
0502 (isempty(jpercent) | ...
0503 icont(i) < jpercent(1))
0504 jpercent = [icont(i) length(code)];
0505 break;
0506 end
0507 end
0508
0509
0510 if ~isempty(jpercent) & ~isempty(jquote)
0511 jquote(find(jquote(:,1) > jpercent(1)),:) = [];
0512 end
0513
0514
0515 icode = [jquote ; jpercent];
0516 splitc = {};
0517 if isempty(icode)
0518 splitc{1} = code;
0519 elseif icode(1,1) > 1
0520 splitc{1} = code(1:icode(1,1)-1);
0521 end
0522 for i=1:size(icode,1)
0523 splitc{end+1} = code(icode(i,1):icode(i,2));
0524 if i < size(icode,1) & icode(i+1,1) > icode(i,2) + 1
0525 splitc{end+1} = code((icode(i,2)+1):(icode(i+1,1)-1));
0526 elseif i == size(icode,1) & icode(i,2) < length(code)
0527 splitc{end+1} = code(icode(i,2)+1:end);
0528 end
0529 end
0530
0531
0532
0533
0534 function [token, remainder, quotient] = strtok(string, delimiters)
0535
0536
0537
0538
0539
0540
0541
0542
0543
0544
0545
0546
0547
0548
0549
0550
0551
0552 token = []; remainder = []; quotient = string;
0553
0554 len = length(string);
0555 if len == 0
0556 return
0557 end
0558
0559 if (nargin == 1)
0560 delimiters = [9:13 32];
0561 end
0562
0563 i = 1;
0564 while (any(string(i) == delimiters))
0565 i = i + 1;
0566 if (i > len), return, end
0567 end
0568 start = i;
0569 while (~any(string(i) == delimiters))
0570 i = i + 1;
0571 if (i > len), break, end
0572 end
0573 finish = i - 1;
0574
0575 token = string(start:finish);
0576
0577 if (nargout >= 2)
0578 remainder = string(finish + 1:length(string));
0579 end
0580
0581 if (nargout == 3 & start > 1)
0582 quotient = string(1:start-1);
0583 else
0584 quotient = [];
0585 end