Thread Subject: pcode and help

Subject: pcode and help

From: Stefan Stoll

Date: 30 Jul, 2001 17:16:58

Message: 1 of 8

  Hi

  I just wanted to prepare a couple of m-files for
  public use. I p-coded all of them to protect my
  source code, but I had to discover that the command
  line help is not working anymore, since help seems
  to be looking for the m-file. The p-file obviously
  doesn't contain the help. Do I really have to embark
  on the tedious task of cutting out the help comments
  from my 100+ m-files? Does anybody have a perl script?
  Is there a workaround?

  --sTefan

Subject: pcode and help

From: Dan Hensley

Date: 30 Jul, 2001 16:02:47

Message: 2 of 8

In article <3B657A6A.75AF0CB1@phys.chem.ethz.ch>, "Stefan Stoll"
<stoll@phys.chem.ethz.ch> wrote:

> Hi
>
> I just wanted to prepare a couple of m-files for public use. I p-coded
> all of them to protect my source code, but I had to discover that the
> command line help is not working anymore, since help seems to be
> looking for the m-file. The p-file obviously doesn't contain the help.
> Do I really have to embark on the tedious task of cutting out the help
> comments from my 100+ m-files? Does anybody have a perl script? Is
> there a workaround?
>
> --sTefan

I think that's the only way to do it. For my code I wrote a simple
Matlab script to do the job. It's not very difficult (just copy the
lines until you hit a blank line, or one that doesn't start with a
comment).

Subject: pcode and help

From: jacklam@math.uio.no (Peter J. Acklam)

Date: 31 Jul, 2001 14:09:55

Message: 3 of 8

Stefan Stoll <stoll@phys.chem.ethz.ch> wrote:

> I just wanted to prepare a couple of m-files for public use. I
> p-coded all of them to protect my source code, but I had to
> discover that the command line help is not working anymore,
> since help seems to be looking for the m-file. The p-file
> obviously doesn't contain the help. Do I really have to
> embark on the tedious task of cutting out the help comments
> from my 100+ m-files? Does anybody have a perl script?

Stripping everything from an m-file except the main help text is
easy. It can, for instance, be done with this compact but
somewhat obscure one-liner

    perl -wne '/^%/?$a=1&&print:$a?last:0' INFILE > OUTFILE

For a more powerful solution, you might want to use the Perl
program which I called ml-strip-code.pl and have included below.
It scans all input directories, with subdirectories, and for each
m-file found, it prints the main help text to an output file in a
user-specified output directory.

Following is how the program is used. Read carefully before using
it. You can also call the program with no input arguments to see
the program usage.

   The first argument is the output directory.
   All following arguments are input directories or files.

   This program scans all input files and directories, with
   subdirectories, and each m-file found is stripped and the
   result is printed to a file in the output directory. Only the
   main help text is printed to the output file. Specifically,
   the help text for subfunctions is not printed. The special
   files Contents.m and Readme.m are copied verbatim. The
   directory structure is preserved in the output directory.

   The output directory must *NOT* be a subdirectory of any input
   directory. The safest thing is to let the output directory be
   a non-existing directory which is not a subdirectory of any
   input directory.

   Existing output files will be overwritten. Symbolic links are
   not followed.

Hope you find it useful.

Peter

----------------------------------------------------------------
#!/local/bin/perl5 -w
#
# ml-strip-code - strip everything except main help text from Matlab m-files
#
# For a usage description, call this program with no input arguments.
#
# Copyright (c) 1999-2001 Peter J. Acklam. All rights reserved.
# This program is free software; you can redistribute it and/or
# modify it under the same terms as Perl itself.
#
# Author: Peter J. Acklam
# Time-stamp: 2001-07-31 12:23:26 +0200
# E-mail: jacklam@math.uio.no
# URL: http://www.math.uio.no/~jacklam

use 5.005;

use strict; # restrict unsafe constructs
use File::Basename; # split a pathname into pieces
use File::Path; # create or remove directory trees
use File::Copy; # copy files or filehandles
use File::Find; # traverse a file tree
use File::Spec; # portably perform operations on file names
use IO::File; # supply object methods for filehandles

my $program = basename $0; # name of this program
my %seen; # directories known to exist

die <<"EOF" unless @ARGV >= 2;
Usage: $program OUTDIR INPUT1 [INPUT2] ...
Strips everything except main help text from Matlab m-files.

The first argument is the output directory.
All following arguments are input directories or files.

This program scans all input files and directories, with subdirectories,
and each m-file found is stripped and the result is printed to a file in
the output directory. Only the main help text is printed to the output
file. Specifically, the help text for subfunctions is not printed. The
special files Contents.m and Readme.m are copied verbatim. The
directory structure is preserved in the output directory.

The output directory must *NOT* be a subdirectory of any input
directory. The safest thing is to let the output directory be a
non-existing directory which is not a subdirectory of any input
directory.

Existing output files will be overwritten. Symbolic links are not
followed.

Report bugs to jacklam\@math.uio.no
EOF

# get name of output directory and check/create
my $outroot = shift @ARGV;
if (! -d $outroot) {
    die "$program: $outroot exists but is not a directory" if -e _;
    mkpath $outroot or die "$program: could not create directory $outroot";
}

# regex for m-files and files to copy verbatim
my $mregex = '\.m$';
my $cregex = '^(?:Contents|Readme)\.m$';

my $is_ms = $^O =~ /^MS/i;
if ($is_ms) {
    # make regexes case insensitive on Microsoft "operating systems"
    $_ = '(?i)' . $_ for ($mregex, $cregex);
}

find {wanted => \&process,
      no_chdir => 1,
     }, @ARGV;

sub process {
    # skip it unless it is an m-file
    return unless /$mregex/o && -f;

    # split input name into name and path (directory)
    my ($name, $path) = fileparse($File::Find::name);

    # output directory
    my $reldir = $path;
    $reldir =~ s/^[A-Za-z]:// if $is_ms; # strip any drive info
    my $odir = File::Spec->join($outroot, $reldir);
    $odir = File::Spec->canonpath($odir);
    if (! $seen{$odir} && ! -d $odir) {
        mkpath $odir or die "$program: could not create directory $odir\n";
        ++$seen{$odir};
    }

    # output file
    my $ofile = File::Spec->join($odir, $name);

    # input file
    my $ifile = File::Spec->canonpath($File::Find::name);

    print "$ifile -> $ofile\n";

    if ($name =~ /$cregex/o) {

        # some files are copied verbatim
        copy $ifile, $ofile or die "$program: failed to copy $ifile: $!\n";

    } else {

        # open input file for reading and output file for writing
        my $ifh = new IO::File $ifile, 'r'
          or die "$program: can't open $ifile for reading: $!\n";
        my $ofh = new IO::File $ofile, 'w'
          or die "$program: can't open $ofile for writing: $!\n";

        # filter the input file, printing only main help to output file
        while (<$ifh>) {
            next unless /^%/;
            print $ofh $_;
            while (<$ifh>) {
                last unless /^%/;
                print $ofh $_;
            }
            last;
        }

        # close input and output files
        $ifh->close;
        $ofh->close;

    }
}

----------------------------------------------------------------

Peter

--
New PNM Toolbox 2.0.0. Patch IMREAD, IMWRITE, IMFINFO or use it as a
separate toolbox. Support for reading and writing PPM, PGM, PBM, RAS,
SGI, and XBM images. Support for images of class double, uint8, and
uint16. <URL: http://www.math.uio.no/~jacklam/matlab/software/pnm/ >

Subject: pcode and help

From: jacklam@math.uio.no (Peter J. Acklam)

Date: 31 Jul, 2001 14:10:22

Message: 4 of 8

"Dan Hensley" <dan.hensley@att.net> wrote:

> I think that's the only way to do it. For my code I wrote a
> simple Matlab script to do the job. It's not very difficult
> (just copy the lines until you hit a blank line, or one that
> doesn't start with a comment).

That should do the trick, as long as you keep in mind that the
main help text doesn't always start at the beginning of a file,
and the first comment in a file isn't necessarily the main help
text.

Peter

--
New PNM Toolbox 2.0.0. Patch IMREAD, IMWRITE, IMFINFO or use it as a
separate toolbox. Support for reading and writing PPM, PGM, PBM, RAS,
SGI, and XBM images. Support for images of class double, uint8, and
uint16. <URL: http://www.math.uio.no/~jacklam/matlab/software/pnm/ >

Subject: pcode and help

From: Dan Hensley

Date: 31 Jul, 2001 14:43:29

Message: 5 of 8

In article <wk3d7d744c.fsf@math.uio.no>, "Peter J. Acklam"
<jacklam@math.uio.no> wrote:

> "Dan Hensley" <dan.hensley@att.net> wrote:
>
>> I think that's the only way to do it. For my code I wrote a simple
>> Matlab script to do the job. It's not very difficult (just copy the
>> lines until you hit a blank line, or one that doesn't start with a
>> comment).
>
> That should do the trick, as long as you keep in mind that the main help
> text doesn't always start at the beginning of a file, and the first
> comment in a file isn't necessarily the main help text.
>
> Peter
>

For me it's always the case since I wrote all the m-code :). But I
thought that Matlab required the main help text to be at the top of the
file?

Dan

Subject: pcode and help

From: hrajagers@my-deja.com (Bert Jagers)

Date: 31 Jul, 2001 10:38:13

Message: 6 of 8

"Dan Hensley" <dan.hensley@att.net> wrote:
> "Stefan Stoll" <stoll@phys.chem.ethz.ch> wrote:
>
> I think that's the only way to do it. For my code I wrote a simple
> Matlab script to do the job. It's not very difficult (just copy the
> lines until you hit a blank line, or one that doesn't start with a
> comment).

Basically that is what this function does ... It performs the pcode
operation, it searches for the first comment block in the m-file
and it writes the appropriate m-file. If there are multiple comment
blocks separated by just blank lines, all will be copied. This is
useful for author and version information that should not be displayed
by the help function.

Let me know if you have suggestions for improvement.

Bert


-----

function pmfile(func,varargin)
%PMFILE Generate p-code and appropriate m-file with help information.
%
% PMFILE(Function,DestDirectory)
% Generate p-code for one function. Function name only, e.g.
% PMFILE('pmfile','d:\').
% The full path of the destination directory should be specified.
%
% PMFILE(SourceDirectory,DestDirectory)
% Generate p-code for a whole directory and all subdirectories.
% The full path of the source and destination directories should
% be specified.
% PMFILE('dir','d:\mfiles\source','d:\mfiles\target')
%
% PMFILE('dir',SourceDirectory,DestDirectory)
% This syntax can be used for directories on the Matlab search path,
% only the last part of the source directory name should be specified.
% PMFILE('dir','specgraph','d:\spec')
%
% NOTES:
% * In all cases the destination directory should exist.
% * Although examples are given for PC platform, this function
% should work similarly for UNIX systems.
%
% See also PCODE.

% (c) 2001, H.R.A. Jagers, bert.jagers@wldelft.nl
% WL | Delft Hydraulics, The Netherlands

% 13/10/2000 : created
% 31/07/2001 : updated

if nargin<2,
  error('Too few input arguments.');
end;

if strcmp(lower(func),'dir') | exist(func)==7
  if exist(func)==7
    dest=varargin{1};
  else
    func=varargin{1};
    dest=varargin{2};
  end
  MP=matlabpath;
  mp=find(MP==pathsep);
  Start=[1 mp+1];
  End=[mp-1 length(MP)];
  P=[];
  for i=1:length(Start),
    if ~isempty(findstr(func,MP(Start(i):End(i))))
      P(end+1)=i;
    end
  end
  if length(P)==1,
    p=MP(Start(P):End(P));
  elseif exist(func)==7 % dir
    p=func;
  else
    error('Cannot uniquely determine directory.')
  end
  pmcodedir(p,dest,1)
else
  dest=varargin{1};
  [p,n,e,v] = fileparts(func);
  if strcmp(lower(e),'.m')
    fullmfile=which(func);
    mfile=n;
  elseif isempty(e)
    fullmfile=which(func);
    mfile=strcat(func,'.m');
  else
    error(sprintf('%s is not an m-file.',func))
  end
  %fprintf('%s -> %s\\%s\n',fullmfile,dest,mfile);
  if ~exist(dest)
    error(sprintf('Destination directory %s does not exist.',dest))
  end
  %
  %[ok,emsg]=copyfile(fullmfile,dest,'writable');
  %
  if isunix
    unix(['cp ',fullmfile,' ',dest]);
  else
    dos(['copy ''',fullmfile,''' ''',dest,''' | exit']);
  end;
  here=pwd;
  try,
    cd(dest);
    if ~strcmp(dest,cd)
      error(sprintf('Could not switch to: %s.',dest));
    end
    pmcodeonefunc(mfile)
  catch,
    warning(lasterr);
  end;
  cd(here);
end

function pmcodedir(p,dest,makecopy)
here=pwd;
try,
  cd(dest)
  d=dir(p);
  if makecopy
    if isunix
      unix(['cp -r ',p,'/* .']);
    else
      dos(['xcopy "',p,'\*.*" "',dest,'" /E | exit']);
    end
  end
  for i=1:length(d)
    [p,n,e,v] = fileparts(d(i).name);
    if isequal(d(i).name,'.') | isequal(d(i).name,'..')
      %don't do anything
    elseif d(i).isdir
      pmcodedir('.',d(i).name,0);
      %fprintf('Skipping subdir %s.\n',d(i).name)
    else
      if strcmp(lower(e),'.m')
        pmcodeonefunc(d(i).name)
      else
      end
    end
  end
catch
  warning(lasterr);
end;
cd(here);

function pmcodeonefunc(mfile)
 % fprintf('Converting ... %s\n',mfile);
Txt = textread(mfile,'%s','delimiter','\n','whitespace','');
i=1;
while i<=length(Txt) & ~strcmp(lower(strtok(Txt{i})),'function'),
  i=i+1;
end;
if i>length(Txt)
  %warning('No function statement found in file!');
  return
else
  try,
    pcode(mfile)
  catch
    fprintf('%s could not be pcoded.\n',mfile);
    return
  end
  fcn=Txt{i};
end
i=1;
while i<=length(Txt) & (isempty(Txt{i}) | Txt{i}(1)~='%'),
  i=i+1;
end;
[fid,emsg]=fopen(mfile,'w');
if fid<0, error(emsg); end
if ~isempty(fcn),
  fprintf(fid,'%s\n',fcn);
end
if i>length(Txt),
  [p,n]=fileparts(mfile);
  fprintf(fid,'%%%s No help available.\n',upper(n));
else,
  i1=i;
  while i<=length(Txt) & ...
    (isempty(Txt{i}) | ((~isempty(Txt{i}) & Txt{i}(1)=='%'))),
    i=i+1;
  end;
  i2=i-1;
  fprintf(fid,'%s\n',Txt{i1:i2});
end;
if ~isempty(fcn)
  fprintf(fid,'\n%s%s\n', ...
      'error(sprintf(''Missing p-file for %s,', ...
            ' contact supplier of code.'',mfilename))');
end
fclose(fid);

Subject: pcode and help

From: jacklam@math.uio.no (Peter J. Acklam)

Date: 31 Jul, 2001 23:07:43

Message: 7 of 8

"Dan Hensley" <dan.hensley@att.net> wrote:

> But I thought that Matlab required the main help text to be at
> the top of the file?

The main help text is the first sequence of comment lines where
each comment start at the beginning of the line.

Here are a few examples, with an m-file called square.m:

The two first comment lines in the following file is not the main
help text, because the first comment does not appear at the
beginning of the line:

----------------------------------------------------------------
   % -*- mode: matlab; coding: iso-8859-1; -*-
   % Copyright (c) Peter J. Acklam. All rights reserved.

function y = square(x)
%SQUARE Square a number.

y = x.^2;
----------------------------------------------------------------

The main help text can appear at the beginning:

----------------------------------------------------------------
%SQUARE Square a number.

function y = square(x)
y = x.^2;
----------------------------------------------------------------

or at the end:

----------------------------------------------------------------
function y = square(x)
y = x.^2;

%SQUARE Square a number.
----------------------------------------------------------------

Peter

--
New PNM Toolbox 2.0.0. Patch IMREAD, IMWRITE, IMFINFO or use it as a
separate toolbox. Support for reading and writing PPM, PGM, PBM, RAS,
SGI, and XBM images. Support for images of class double, uint8, and
uint16. <URL: http://www.math.uio.no/~jacklam/matlab/software/pnm/ >

Subject: pcode and help

From: Jason Breslau

Date: 28 Jan, 2011 17:41:04

Message: 8 of 8

Your best bet at finding the text from the file which is considered the help is to call help.

helpText = help(<filename>);

Now you have the help text as a string. Help replaced the % characters with spaces, so you need to put them back:

helpText = regexprep(helpText, '^ ', '%', 'lineanchors')

Now you can open a file and write just the help text into it.

Share and Enjoy,

-=>J

Stefan Stoll <stoll@phys.chem.ethz.ch> wrote in message <3B657A6A.75AF0CB1@phys.chem.ethz.ch>...
> Hi
>
> I just wanted to prepare a couple of m-files for
> public use. I p-coded all of them to protect my
> source code, but I had to discover that the command
> line help is not working anymore, since help seems
> to be looking for the m-file. The p-file obviously
> doesn't contain the help. Do I really have to embark
> on the tedious task of cutting out the help comments
> from my 100+ m-files? Does anybody have a perl script?
> Is there a workaround?
>
> --sTefan

Tags for this Thread

Add a New Tag:

Separated by commas
Ex.: root locus, bode

What are tags?

A tag is like a keyword or category label associated with each thread. Tags make it easier for you to find threads of interest.

Anyone can tag a thread. Tags are public and visible to everyone.

rssFeed for this Thread

Contact us at files@mathworks.com