view scripts/path/savepath.m @ 30875:5d3faba0342e

doc: Ensure documentation lists output argument when it exists for all m-files. For new users of Octave it is best to show explicit calling forms in the documentation and to show a return argument when it exists. * bp-table.cc, shift.m, accumarray.m, accumdim.m, bincoeff.m, bitcmp.m, bitget.m, bitset.m, blkdiag.m, celldisp.m, cplxpair.m, dblquad.m, flip.m, fliplr.m, flipud.m, idivide.m, int2str.m, interpft.m, logspace.m, num2str.m, polyarea.m, postpad.m, prepad.m, randi.m, repmat.m, rng.m, rot90.m, rotdim.m, structfun.m, triplequad.m, uibuttongroup.m, uicontrol.m, uipanel.m, uipushtool.m, uitoggletool.m, uitoolbar.m, waitforbuttonpress.m, help.m, __additional_help_message__.m, hsv.m, im2double.m, im2frame.m, javachk.m, usejava.m, argnames.m, char.m, formula.m, inline.m, __vectorize__.m, findstr.m, flipdim.m, strmatch.m, vectorize.m, commutation_matrix.m, cond.m, cross.m, duplication_matrix.m, expm.m, orth.m, rank.m, rref.m, trace.m, vech.m, cast.m, compare_versions.m, delete.m, dir.m, fileattrib.m, grabcode.m, gunzip.m, inputname.m, license.m, list_primes.m, ls.m, mexext.m, movefile.m, namelengthmax.m, nargoutchk.m, nthargout.m, substruct.m, swapbytes.m, ver.m, verLessThan.m, what.m, fminunc.m, fsolve.m, fzero.m, optimget.m, __fdjac__.m, matlabroot.m, savepath.m, campos.m, camroll.m, camtarget.m, camup.m, camva.m, camzoom.m, clabel.m, diffuse.m, legend.m, orient.m, rticks.m, specular.m, thetaticks.m, xlim.m, xtickangle.m, xticklabels.m, xticks.m, ylim.m, ytickangle.m, yticklabels.m, yticks.m, zlim.m, ztickangle.m, zticklabels.m, zticks.m, ellipsoid.m, isocolors.m, isonormals.m, stairs.m, surfnorm.m, __actual_axis_position__.m, __pltopt__.m, close.m, graphics_toolkit.m, pan.m, print.m, printd.m, __ghostscript__.m, __gnuplot_print__.m, __opengl_print__.m, rotate3d.m, subplot.m, zoom.m, compan.m, conv.m, poly.m, polyaffine.m, polyder.m, polyint.m, polyout.m, polyreduce.m, polyvalm.m, roots.m, prefdir.m, prefsfile.m, profexplore.m, profexport.m, profshow.m, powerset.m, unique.m, arch_rnd.m, arma_rnd.m, autoreg_matrix.m, bartlett.m, blackman.m, detrend.m, durbinlevinson.m, fftconv.m, fftfilt.m, fftshift.m, fractdiff.m, hamming.m, hanning.m, hurst.m, ifftshift.m, rectangle_lw.m, rectangle_sw.m, triangle_lw.m, sinc.m, sinetone.m, sinewave.m, spectral_adf.m, spectral_xdf.m, spencer.m, ilu.m, __sprand__.m, sprand.m, sprandn.m, sprandsym.m, treelayout.m, beta.m, betainc.m, betaincinv.m, betaln.m, cosint.m, expint.m, factorial.m, gammainc.m, gammaincinv.m, lcm.m, nthroot.m, perms.m, reallog.m, realpow.m, realsqrt.m, sinint.m, hadamard.m, hankel.m, hilb.m, invhilb.m, magic.m, pascal.m, rosser.m, toeplitz.m, vander.m, wilkinson.m, center.m, corr.m, cov.m, discrete_cdf.m, discrete_inv.m, discrete_pdf.m, discrete_rnd.m, empirical_cdf.m, empirical_inv.m, empirical_pdf.m, empirical_rnd.m, kendall.m, kurtosis.m, mad.m, mean.m, meansq.m, median.m, mode.m, moment.m, range.m, ranks.m, run_count.m, skewness.m, spearman.m, statistics.m, std.m, base2dec.m, bin2dec.m, blanks.m, cstrcat.m, deblank.m, dec2base.m, dec2bin.m, dec2hex.m, hex2dec.m, index.m, regexptranslate.m, rindex.m, strcat.m, strjust.m, strtrim.m, strtrunc.m, substr.m, untabify.m, __have_feature__.m, __prog_output_assert__.m, __run_test_suite__.m, example.m, fail.m, asctime.m, calendar.m, ctime.m, date.m, etime.m: Add return arguments to @deftypefn macros where they were missing. Rename variables in functions (particularly generic "retval") to match documentation. Rename some return variables for (hopefully) better clarity (e.g., 'ax' to 'hax' to indicate it is a graphics handle to an axes object).
author Rik <rik@octave.org>
date Wed, 30 Mar 2022 20:40:27 -0700
parents 796f54d4ddbf
children 597f3ee61a48
line wrap: on
line source

########################################################################
##
## Copyright (C) 2005-2022 The Octave Project Developers
##
## See the file COPYRIGHT.md in the top-level directory of this
## distribution or <https://octave.org/copyright/>.
##
## This file is part of Octave.
##
## Octave is free software: you can redistribute it and/or modify it
## under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## Octave is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with Octave; see the file COPYING.  If not, see
## <https://www.gnu.org/licenses/>.
##
########################################################################

## -*- texinfo -*-
## @deftypefn  {} {} savepath
## @deftypefnx {} {} savepath @var{file}
## @deftypefnx {} {@var{status} =} savepath (@dots{})
## Save the unique portion of the current function search path that is
## not set during Octave's initialization process to @var{file}.
##
## If @var{file} is omitted, Octave looks in the current directory for a
## project-specific @file{.octaverc} file in which to save the path
## information.  If no such file is present then the user's configuration file
## @file{~/.octaverc} is used.
##
## If successful, @code{savepath} returns 0.
##
## The @code{savepath} function makes it simple to customize a user's
## configuration file to restore the working paths necessary for a particular
## instance of Octave.  Assuming no filename is specified, Octave will
## automatically restore the saved directory paths from the appropriate
## @file{.octaverc} file when starting up.  If a filename has been specified
## then the paths may be restored manually by calling @code{source @var{file}}.
## @seealso{path, addpath, rmpath, genpath, pathdef}
## @end deftypefn

function status = savepath (file)

  beginstring = "## Begin savepath auto-created section, do not edit";
  endstring   = "## End savepath auto-created section";

  ## Use project-specific or user's .octaverc when no file specified
  if (nargin == 0)
    file = fullfile (pwd, ".octaverc");
    if (! exist (file, "file"))
      file = fullfile ("~", ".octaverc");
    endif
  endif

  ## Read in the file
  [filelines, startline, endline] = getsavepath (file);

  ## Determine where the savepath lines are placed in the file.
  if (isempty (filelines)
      || (startline == 1 && endline == length (filelines)))
    ## savepath is the entire file.
    pre = post = {};
  elseif (endline == 0)
    ## Drop the savepath statements at the end of the file.
    pre = filelines;
    post = {};
  elseif (startline == 1)
    pre = {};
    post = filelines(endline+1:end);
  elseif (endline == length (filelines))
    pre = filelines(1:startline-1);
    post = {};
  else
    ## Insert in the middle.
    pre = filelines(1:startline-1);
    post = filelines(endline+1:end);
  endif

  ## Write the results.
  [fid, msg] = fopen (file, "wt");
  if (fid < 0)
    error ("savepath: unable to open FILE for writing, %s, %s", file, msg);
  endif
  unwind_protect
    fprintf (fid, "%s\n", pre{:});

    ## Remove the portion of the path defined via the command line
    ## and/or the environment.
    workingpath = parsepath (path);
    cmd_line_path = parsepath (command_line_path ());
    octave_path = parsepath (getenv ("OCTAVE_PATH"));
    default_path = pathdef ();
    if (isempty (default_path))
      ## This occurs when running octave via run-octave.  In this instance
      ## the entire path is specified via the command line and pathdef()
      ## is empty.
      [~, n] = setdiff (workingpath, octave_path);
      default_path = cmd_line_path;
    else
      [~, n] = setdiff (workingpath, union (cmd_line_path, octave_path));
      default_path = parsepath (default_path);
    endif
    ## This is the path we'd like to preserve when octave is run.
    path_to_preserve = workingpath(sort (n));

    ## Determine the path to Octave's user and system wide packages.
    [pkg_user, pkg_system] = pkg ("list");

    ## Conversion from cell array of structs to cellstr of archprefixes.
    pkg_path = unique (cellfun (@(elt) elt.archprefix,
                                [pkg_user, pkg_system],
                                "uniformoutput", false));

    ## Rely on Octave's initialization to include the pkg path elements.
    if (! isempty (pkg_path))
      [~, n] = setdiff (path_to_preserve, strcat (pkg_path, ":"));
      path_to_preserve = path_to_preserve(sort (n));
    endif

    ## Split the path to be saved into two groups.  Those path elements that
    ## belong at the beginning and those at the end.
    if (! isempty (default_path))
      n1 = find (strcmp (default_path{1}, path_to_preserve));
      n2 = find (strcmp (default_path{end}, path_to_preserve));
      n_middle = round ((n1+n2)/2);
      [~, n] = setdiff (path_to_preserve, default_path);
      path_to_save = path_to_preserve(sort (n));
      ## Remove pwd
      path_to_save(strcmp (path_to_save, ["." pathsep])) = [];
      if (! isempty (path_to_save))
        n = ones (numel (path_to_save), 1);
        for m = 1:numel (path_to_save)
          n(m) = find (strcmp (path_to_save{m}, path_to_preserve));
        endfor
        path_to_save_begin = path_to_save(n <= n_middle);
        path_to_save_end   = path_to_save(n > n_middle);
      else
        path_to_save_begin = {};
        path_to_save_end   = {};
      endif
    else
      path_to_save_begin = path_to_preserve;
      path_to_save_end   = {};
    endif
    path_to_save_begin = cell2mat (path_to_save_begin);
    path_to_save_end   = cell2mat (path_to_save_end);

    ## Use single quotes for PATH argument to avoid string escape
    ## processing.  Since we are using single quotes around the arg,
    ## double any single quote characters found in the string.
    fprintf (fid, "%s\n", beginstring);
    if (! isempty (path_to_save_begin))
      n = find (path_to_save_begin != pathsep, 1, "last");
      fprintf (fid, "  addpath ('%s', '-begin');\n",
               strrep (path_to_save_begin(1:n), "'", "''"));
    endif
    if (! isempty (path_to_save_end))
      n = find (path_to_save_end != pathsep, 1, "last");
      fprintf (fid, "  addpath ('%s', '-end');\n",
               strrep (path_to_save_end(1:n), "'", "''"));
    endif
    fprintf (fid, "%s\n", endstring);

    fprintf (fid, "%s\n", post{:});
  unwind_protect_cleanup
    sts = fclose (fid);
    if (sts < 0)
      error ("savepath: could not close savefile after writing, %s", file);
    elseif (nargin == 0)
      warning ("off", "backtrace", "local");
      warning ("Octave:savepath-local",
               "savepath: current path saved to %s", file);
    endif
  end_unwind_protect

  if (nargout > 0)
    status = 0;
  endif

endfunction

## Convert single string of paths to cell array of paths
function path_elements = parsepath (p)
  path_elements = strcat (ostrsplit (p, pathsep), pathsep);
endfunction


%!test
%! fname = tempname ();
%! test_dir = tempname ();
%! unwind_protect
%!   if (! mkdir (test_dir))
%!     error ("unable to create directory for tests");
%!   endif
%!   status = savepath (fname);
%!   assert (status == 0);
%!   old_dir = pwd ();
%!   unwind_protect
%!     cd (test_dir);
%!     if (exist (fullfile (pwd, ".octaverc")))
%!       unlink (".octaverc");
%!     endif
%!     ## Create blank .octaverc file
%!     fid = fopen (".octaverc", "wt");
%!     assert (fid >= 0);
%!     fclose (fid);
%!     ## Save path into local .octaverc file
%!     warning ("off", "Octave:savepath-local", "local");
%!     status = savepath ();
%!     assert (status == 0);
%!     ## Compare old and new versions
%!     fid = fopen (fname, "rb");
%!     assert (fid >= 0);
%!     orig_data = fread (fid);
%!     fclose (fid);
%!     fid = fopen (".octaverc", "rb");
%!     assert (fid >= 0);
%!     new_data = fread (fid);
%!     fclose (fid);
%!     assert (orig_data, new_data);
%!   unwind_protect_cleanup
%!     cd (old_dir);
%!   end_unwind_protect
%! unwind_protect_cleanup
%!   confirm_recursive_rmdir (false, "local");
%!   sts = rmdir (test_dir, "s");
%!   unlink (fname);
%! end_unwind_protect