]> Creatis software - CreaPhase.git/blob - octave_packages/m/pkg/pkg.m
update packages
[CreaPhase.git] / octave_packages / m / pkg / pkg.m
1 ## Copyright (C) 2005-2012 S�ren Hauberg
2 ## Copyright (C) 2010 VZLU Prague, a.s.
3 ##
4 ## This file is part of Octave.
5 ##
6 ## Octave is free software; you can redistribute it and/or modify it
7 ## under the terms of the GNU General Public License as published by
8 ## the Free Software Foundation; either version 3 of the License, or (at
9 ## your option) any later version.
10 ##
11 ## Octave is distributed in the hope that it will be useful, but
12 ## WITHOUT ANY WARRANTY; without even the implied warranty of
13 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 ## General Public License for more details.
15 ##
16 ## You should have received a copy of the GNU General Public License
17 ## along with Octave; see the file COPYING.  If not, see
18 ## <http://www.gnu.org/licenses/>.
19
20 ## -*- texinfo -*-
21 ## @deftypefn  {Command} {} pkg @var{command} @var{pkg_name}
22 ## @deftypefnx {Command} {} pkg @var{command} @var{option} @var{pkg_name}
23 ## Manage packages (groups of add-on functions) for Octave.  Different actions
24 ## are available depending on the value of @var{command}.
25 ##
26 ## Available commands:
27 ##
28 ## @table @samp
29 ##
30 ## @item install
31 ## Install named packages.  For example,
32 ##
33 ## @example
34 ## pkg install image-1.0.0.tar.gz
35 ## @end example
36 ##
37 ## @noindent
38 ## installs the package found in the file @file{image-1.0.0.tar.gz}.
39 ##
40 ## The @var{option} variable can contain options that affect the manner
41 ## in which a package is installed.  These options can be one or more of
42 ##
43 ## @table @code
44 ## @item -nodeps
45 ## The package manager will disable dependency checking.  With this option it
46 ## is possible to install a package even when it depends on another package
47 ## which is not installed on the system.  @strong{Use this option with care.}
48 ##
49 ## @item -noauto
50 ## The package manager will not automatically load the installed package
51 ## when starting Octave.  This overrides any setting within the package.
52 ##
53 ## @item -auto
54 ## The package manager will automatically load the installed package when
55 ## starting Octave.  This overrides any setting within the package.
56 ##
57 ## @item -local
58 ## A local installation (package available only to current user) is forced,
59 ## even if the user has system privileges.
60 ##
61 ## @item -global
62 ## A global installation (package available to all users) is forced, even if
63 ## the user doesn't normally have system privileges.
64 ##
65 ## @item -forge
66 ## Install a package directly from the Octave-Forge repository.  This
67 ## requires an internet connection and the cURL library.
68 ##
69 ## @item -verbose
70 ## The package manager will print the output of all commands as
71 ## they are performed.
72 ## @end table
73 ##
74 ## @item update
75 ## Check installed Octave-Forge packages against repository and update any
76 ## outdated items.  This requires an internet connection and the cURL library.
77 ## Usage:
78 ##
79 ## @example
80 ## pkg update
81 ## @end example
82 ##
83 ## @item uninstall
84 ## Uninstall named packages.  For example,
85 ##
86 ## @example
87 ## pkg uninstall image
88 ## @end example
89 ##
90 ## @noindent
91 ## removes the @code{image} package from the system.  If another installed
92 ## package depends on the @code{image} package an error will be issued.
93 ## The package can be uninstalled anyway by using the @option{-nodeps} option.
94 ##
95 ## @item load
96 ## Add named packages to the path.  After loading a package it is
97 ## possible to use the functions provided by the package.  For example,
98 ##
99 ## @example
100 ## pkg load image
101 ## @end example
102 ##
103 ## @noindent
104 ## adds the @code{image} package to the path.  It is possible to load all
105 ## installed packages at once with the keyword @samp{all}.  Usage:
106 ##
107 ## @example
108 ## pkg load all
109 ## @end example
110 ##
111 ## @item unload
112 ## Remove named packages from the path.  After unloading a package it is
113 ## no longer possible to use the functions provided by the package.  It is
114 ## possible to unload all installed packages at once with the keyword
115 ## @samp{all}.  Usage:
116 ##
117 ## @example
118 ## pkg unload all
119 ## @end example
120 ##
121 ## @item list
122 ## Show the list of currently installed packages.  For example,
123 ##
124 ## @example
125 ## installed_packages = pkg ("list")
126 ## @end example
127 ##
128 ## @noindent
129 ## returns a cell array containing a structure for each installed package.
130 ##
131 ## If two output arguments are requested @code{pkg} splits the list of
132 ## installed packages into those which were installed by the current user,
133 ## and those which were installed by the system administrator.
134 ##
135 ## @example
136 ## [user_packages, system_packages] = pkg ("list")
137 ## @end example
138 ##
139 ## The option '-forge' lists packages available at the Octave-Forge repository.
140 ## This requires an internet connection and the cURL library.  For example:
141 ##
142 ## @example
143 ## oct_forge_pkgs = pkg ("list", "-forge")
144 ## @end example
145 ##
146 ## @item describe
147 ## Show a short description of the named installed packages, with the option
148 ## '-verbose' also list functions provided by the package.  For example,
149 ##
150 ## @example
151 ## pkg describe -verbose all
152 ## @end example
153 ##
154 ## @noindent
155 ## will describe all installed packages and the functions they provide.
156 ## If one output is requested a cell of structure containing the
157 ## description and list of functions of each package is returned as
158 ## output rather than printed on screen:
159 ##
160 ## @example
161 ## desc = pkg ("describe", "secs1d", "image")
162 ## @end example
163 ##
164 ## @noindent
165 ## If any of the requested packages is not installed, pkg returns an
166 ## error, unless a second output is requested:
167 ##
168 ## @example
169 ## [desc, flag] = pkg ("describe", "secs1d", "image")
170 ## @end example
171 ##
172 ## @noindent
173 ## @var{flag} will take one of the values "Not installed", "Loaded" or
174 ## "Not loaded" for each of the named packages.
175 ##
176 ## @item prefix
177 ## Set the installation prefix directory.  For example,
178 ##
179 ## @example
180 ## pkg prefix ~/my_octave_packages
181 ## @end example
182 ##
183 ## @noindent
184 ## sets the installation prefix to @file{~/my_octave_packages}.
185 ## Packages will be installed in this directory.
186 ##
187 ## It is possible to get the current installation prefix by requesting an
188 ## output argument.  For example:
189 ##
190 ## @example
191 ## pfx = pkg ("prefix")
192 ## @end example
193 ##
194 ## The location in which to install the architecture dependent files can be
195 ## independently specified with an addition argument.  For example:
196 ##
197 ## @example
198 ## pkg prefix ~/my_octave_packages ~/my_arch_dep_pkgs
199 ## @end example
200 ##
201 ## @item local_list
202 ## Set the file in which to look for information on locally
203 ## installed packages.  Locally installed packages are those that are
204 ## available only to the current user.  For example:
205 ##
206 ## @example
207 ## pkg local_list ~/.octave_packages
208 ## @end example
209 ##
210 ## It is possible to get the current value of local_list with the following
211 ##
212 ## @example
213 ## pkg local_list
214 ## @end example
215 ##
216 ## @item global_list
217 ## Set the file in which to look for information on globally
218 ## installed packages.  Globally installed packages are those that are
219 ## available to all users.  For example:
220 ##
221 ## @example
222 ## pkg global_list /usr/share/octave/octave_packages
223 ## @end example
224 ##
225 ## It is possible to get the current value of global_list with the following
226 ##
227 ## @example
228 ## pkg global_list
229 ## @end example
230 ##
231 ## @item build
232 ## Build a binary form of a package or packages.  The binary file produced
233 ## will itself be an Octave package that can be installed normally with
234 ## @code{pkg}.  The form of the command to build a binary package is
235 ##
236 ## @example
237 ## pkg build builddir image-1.0.0.tar.gz @dots{}
238 ## @end example
239 ##
240 ## @noindent
241 ## where @code{builddir} is the name of a directory where the temporary
242 ## installation will be produced and the binary packages will be found.
243 ## The options @option{-verbose} and @option{-nodeps} are respected, while
244 ## all other options are ignored.
245 ##
246 ## @item rebuild
247 ## Rebuild the package database from the installed directories.  This can
248 ## be used in cases where the package database has been corrupted.
249 ## It can also take the @option{-auto} and @option{-noauto} options to allow the
250 ## autoloading state of a package to be changed.  For example,
251 ##
252 ## @example
253 ## pkg rebuild -noauto image
254 ## @end example
255 ##
256 ## @noindent
257 ## will remove the autoloading status of the image package.
258 ##
259 ## @end table
260 ## @end deftypefn
261
262 function [local_packages, global_packages] = pkg (varargin)
263   ## Installation prefix (FIXME: what should these be on windows?)
264   persistent user_prefix = false;
265   persistent prefix = -1;
266   persistent archprefix = -1;
267   persistent local_list = tilde_expand (fullfile ("~", ".octave_packages"));
268   persistent global_list = fullfile (OCTAVE_HOME (), "share", "octave",
269                                      "octave_packages");
270   mlock ();
271
272   global_install = issuperuser ();
273
274   if (prefix == -1)
275     if (global_install)
276       prefix = fullfile (OCTAVE_HOME (), "share", "octave", "packages");
277       archprefix = fullfile (octave_config_info ("libdir"),
278                              "octave", "packages");
279     else
280       prefix = fullfile ("~", "octave");
281       archprefix = prefix;
282     endif
283     prefix = tilde_expand (prefix);
284     archprefix = tilde_expand (archprefix);
285   endif
286
287   available_actions = {"list", "install", "uninstall", "load", ...
288                        "unload", "prefix", "local_list", ...
289                        "global_list", "rebuild", "build", ...
290                        "describe", "update"};
291   ## Handle input
292   if (length (varargin) == 0 || ! iscellstr (varargin))
293     print_usage ();
294   endif
295   files = {};
296   deps = true;
297   auto = 0;
298   action = "none";
299   verbose = false;
300   octave_forge = false;
301   for i = 1:length (varargin)
302     switch (varargin{i})
303       case "-nodeps"
304         deps = false;
305       case "-noauto"
306         auto = -1;
307       case "-auto"
308         auto = 1;
309       case "-verbose"
310         verbose = true;
311         ## Send verbose output to pager immediately.  Change setting locally.
312         page_output_immediately (true, "local");
313       case "-forge"
314         octave_forge = true;
315       case "-local"
316         global_install = false;
317         if (! user_prefix)
318           prefix = tilde_expand (fullfile ("~", "octave"));
319           archprefix = prefix;
320         endif
321       case "-global"
322         global_install = true;
323         if (! user_prefix)
324           prefix = fullfile (OCTAVE_HOME (), "share", "octave", "packages");
325           archprefix = fullfile (octave_config_info ("libdir"),
326                                  "octave", "packages");
327         endif
328       case available_actions
329         if (strcmp (action, "none"))
330           action = varargin{i};
331         else
332           error ("more than one action specified");
333         endif
334       otherwise
335         files{end+1} = varargin{i};
336     endswitch
337   endfor
338
339   if (octave_forge && ! any (strcmp (action, {"install", "list"})))
340     error ("-forge can only be used with install or list");
341   endif
342
343   ## Take action
344   switch (action)
345     case "list"
346       if (octave_forge)
347         if (nargout > 0)
348           local_packages = list_forge_packages ();
349         else
350           list_forge_packages ();
351         endif
352       else
353         if (nargout == 0)
354           installed_packages (local_list, global_list);
355         elseif (nargout == 1)
356           local_packages = installed_packages (local_list, global_list);
357         elseif (nargout == 2)
358           [local_packages, global_packages] = installed_packages (local_list,
359                                                                   global_list);
360         else
361           error ("too many output arguments requested");
362         endif
363       endif
364
365     case "install"
366       if (length (files) == 0)
367         error ("you must specify at least one filename when calling 'pkg install'");
368       endif
369
370       local_files = {};
371       unwind_protect
372
373         if (octave_forge)
374           [urls, local_files] = cellfun ("get_forge_download", files, "uniformoutput", false);
375           [files, succ] = cellfun ("urlwrite", urls, local_files, "uniformoutput", false);
376           succ = [succ{:}];
377           if (! all (succ))
378             i = find (! succ, 1);
379             error ("could not download file %s from url %s", local_files{i}, urls{i});
380           endif
381         endif
382
383         install (files, deps, auto, prefix, archprefix, verbose, local_list,
384                  global_list, global_install);
385
386       unwind_protect_cleanup
387         cellfun ("unlink", local_files);
388       end_unwind_protect
389
390     case "uninstall"
391       if (length (files) == 0)
392         error ("you must specify at least one package when calling 'pkg uninstall'");
393       endif
394       uninstall (files, deps, verbose, local_list,
395                  global_list, global_install);
396
397     case "load"
398       if (length (files) == 0)
399         error ("you must specify at least one package, 'all' or 'auto' when calling 'pkg load'");
400       endif
401       load_packages (files, deps, local_list, global_list);
402
403     case "unload"
404       if (length (files) == 0)
405         error ("you must specify at least one package or 'all' when calling 'pkg unload'");
406       endif
407       unload_packages (files, deps, local_list, global_list);
408
409     case "prefix"
410       if (length (files) == 0 && nargout == 0)
411         printf ("Installation prefix:             %s\n", prefix);
412         printf ("Architecture dependent prefix:   %s\n", archprefix);
413       elseif (length (files) == 0 && nargout >= 1)
414         local_packages = prefix;
415         global_packages = archprefix;
416       elseif (length (files) >= 1 && nargout <= 2 && ischar (files{1}))
417         prefix = files{1};
418         prefix = absolute_pathname (prefix);
419         local_packages = prefix;
420         user_prefix = true;
421         if (length (files) >= 2 && ischar (files{2}))
422           archprefix = files{2};
423           try
424             archprefix = absolute_pathname (archprefix);
425           catch
426             mkdir (archprefix);
427             warning ("creating the directory %s\n", archprefix);
428             archprefix = absolute_pathname (archprefix);
429           end_try_catch
430           global_packages = archprefix;
431         endif
432       else
433         error ("you must specify a prefix directory, or request an output argument");
434       endif
435
436     case "local_list"
437       if (length (files) == 0 && nargout == 0)
438         disp (local_list);
439       elseif (length (files) == 0 && nargout == 1)
440         local_packages = local_list;
441       elseif (length (files) == 1 && nargout == 0 && ischar (files{1}))
442         try
443           local_list = absolute_pathname (files{1});
444         catch
445           ## Force file to be created
446           fclose (fopen (files{1}, "wt"));
447           local_list = absolute_pathname (files{1});
448         end_try_catch
449       else
450         error ("you must specify a local_list file, or request an output argument");
451       endif
452
453     case "global_list"
454       if (length (files) == 0 && nargout == 0)
455         disp(global_list);
456       elseif (length (files) == 0 && nargout == 1)
457         local_packages = global_list;
458       elseif (length (files) == 1 && nargout == 0 && ischar (files{1}))
459         try
460           global_list = absolute_pathname (files{1});
461         catch
462           ## Force file to be created
463           fclose (fopen (files{1}, "wt"));
464           global_list = absolute_pathname (files{1});
465         end_try_catch
466       else
467         error ("you must specify a global_list file, or request an output argument");
468       endif
469
470     case "rebuild"
471       if (global_install)
472         global_packages = rebuild (prefix, archprefix, global_list, files,
473                                    auto, verbose);
474         global_packages = save_order (global_packages);
475         save (global_list, "global_packages");
476         if (nargout > 0)
477           local_packages = global_packages;
478         endif
479       else
480         local_packages = rebuild (prefix, archprefix, local_list, files, auto,
481                                   verbose);
482         local_packages = save_order (local_packages);
483         save (local_list, "local_packages");
484         if (nargout == 0)
485           clear ("local_packages");
486         endif
487       endif
488
489     case "build"
490       if (length (files) < 2)
491         error ("you must specify at least the build directory and one filename\nwhen calling 'pkg build'");
492       endif
493       build (files, deps, auto, verbose);
494
495     case "describe"
496       if (length (files) == 0)
497         error ("you must specify at least one package or 'all' when calling 'pkg describe'");
498       endif
499       ## FIXME: the name of the output variables is inconsistent
500       ##            with their content
501       switch (nargout)
502         case 0
503           describe (files, verbose, local_list, global_list);
504         case 1
505           pkg_desc_list = describe (files, verbose, local_list, ...
506                                     global_list);
507           local_packages = pkg_desc_list;
508         case 2
509           [pkg_desc_list, flag] = describe (files, verbose, local_list, ...
510                                             global_list);
511           local_packages  = pkg_desc_list;
512           global_packages = flag;
513         otherwise
514           error ("you can request at most two outputs when calling 'pkg describe'");
515       endswitch
516
517     case "update"
518       if (nargout == 0)
519         installed_pkgs_lst = installed_packages (local_list, global_list);
520         for i = 1:length (installed_pkgs_lst)
521           installed_pkg_name = installed_pkgs_lst{i}.name;
522           installed_pkg_version = installed_pkgs_lst{i}.version;
523           forge_pkg_version = get_forge_pkg (installed_pkg_name);
524           if (compare_versions (forge_pkg_version, installed_pkg_version, ">"))
525             feval (@pkg, "install", "-forge", installed_pkg_name);
526           endif
527         endfor
528       else
529         error ("no output arguments available");
530       endif
531
532     otherwise
533       error ("you must specify a valid action for 'pkg'. See 'help pkg' for details");
534   endswitch
535 endfunction
536
537 function descriptions = rebuild (prefix, archprefix, list, files, auto, verbose)
538   if (isempty (files))
539     [dirlist, err, msg] = readdir (prefix);
540     if (err)
541       error ("couldn't read directory %s: %s", prefix, msg);
542     endif
543     ## the two first entries of dirlist are "." and ".."
544     dirlist([1,2]) = [];
545   else
546     old_descriptions = installed_packages (list, list);
547     wd = pwd ();
548     unwind_protect
549       cd (prefix);
550       dirlist = glob (cellfun(@(x) cstrcat(x, '-*'), files, 'uniformoutput', 0));
551     unwind_protect_cleanup
552       cd (wd);
553     end_unwind_protect
554   endif
555   descriptions = {};
556   for k = 1:length (dirlist)
557     descfile = fullfile (prefix, dirlist{k}, "packinfo", "DESCRIPTION");
558     if (verbose)
559       printf ("recreating package description from %s\n", dirlist{k});
560     endif
561     if (exist (descfile, "file"))
562       desc = get_description (descfile);
563       desc.dir = fullfile (prefix, dirlist{k});
564       desc.archprefix = fullfile (archprefix, cstrcat (desc.name, "-",
565                                   desc.version));
566       if (auto != 0)
567         if (exist (fullfile (desc.dir, "packinfo", ".autoload"), "file"))
568           unlink (fullfile (desc.dir, "packinfo", ".autoload"));
569         endif
570         if (auto < 0)
571           desc.autoload = 0;
572         elseif (auto > 0)
573           desc.autoload = 1;
574           fclose (fopen (fullfile (desc.dir, "packinfo", ".autoload"), "wt"));
575         endif
576       else
577         if (exist (fullfile (desc.dir, "packinfo", ".autoload"), "file"))
578           desc.autoload = 1;
579         else
580           desc.autoload = 0;
581         endif
582       endif
583       descriptions{end + 1} = desc;
584     elseif (verbose)
585       warning ("directory %s is not a valid package", dirlist{k});
586     endif
587   endfor
588
589   if (! isempty (files))
590     ## We are rebuilding for a particular package(s) so we should take
591     ## care to keep the other untouched packages in the descriptions
592     descriptions = {descriptions{:}, old_descriptions{:}};
593
594     dup = [];
595     for i = 1:length (descriptions)
596       if (find (dup, i))
597         continue;
598       endif
599       for j = (i+1):length (descriptions)
600         if (find (dup, j))
601           continue;
602         endif
603         if (strcmp (descriptions{i}.name, descriptions{j}.name))
604           dup = [dup, j];
605         endif
606       endfor
607     endfor
608     if (! isempty (dup))
609       descriptions (dup) = [];
610     endif
611   endif
612 endfunction
613
614 function build (files, handle_deps, autoload, verbose)
615   if (length (files) < 1)
616     error ("insufficient number of files");
617   endif
618   builddir = files{1};
619   if (! exist (builddir, "dir"))
620     warning ("creating build directory %s", builddir);
621     [status, msg] = mkdir (builddir);
622     if (status != 1)
623       error ("could not create installation directory: %s", msg);
624     endif
625   endif
626   builddir = absolute_pathname (builddir);
627   installdir = fullfile (builddir, "install");
628   if (! exist (installdir, "dir"))
629     [status, msg] = mkdir (installdir);
630     if (status != 1)
631       error ("could not create installation directory: %s", msg);
632     endif
633   endif
634   files(1) = [];
635   buildlist = fullfile (builddir, "octave_packages");
636   install (files, handle_deps, autoload, installdir, installdir, verbose,
637            buildlist, "", false);
638   unwind_protect
639     repackage (builddir, buildlist);
640   unwind_protect_cleanup
641     unload_packages ({"all"}, handle_deps, buildlist, "");
642     if (exist (installdir, "dir"))
643       rm_rf (installdir);
644     endif
645     if (exist (buildlist, "file"))
646       unlink (buildlist);
647     endif
648   end_unwind_protect
649 endfunction
650
651 function install (files, handle_deps, autoload, prefix, archprefix, verbose,
652                   local_list, global_list, global_install)
653
654   ## Check that the directory in prefix exist. If it doesn't: create it!
655   if (! exist (prefix, "dir"))
656     warning ("creating installation directory %s", prefix);
657     [status, msg] = mkdir (prefix);
658     if (status != 1)
659       error ("could not create installation directory: %s", msg);
660     endif
661   endif
662
663   ## Get the list of installed packages.
664   [local_packages, global_packages] = installed_packages (local_list,
665                                                           global_list);
666
667   installed_pkgs_lst = {local_packages{:}, global_packages{:}};
668
669   if (global_install)
670     packages = global_packages;
671   else
672     packages = local_packages;
673   endif
674
675   ## Uncompress the packages and read the DESCRIPTION files.
676   tmpdirs = packdirs = descriptions = {};
677   try
678     ## Warn about non existent files.
679     for i = 1:length (files)
680       if (isempty (glob(files{i})))
681         warning ("file %s does not exist", files{i});
682       endif
683     endfor
684
685     ## Unpack the package files and read the DESCRIPTION files.
686     files = glob (files);
687     packages_to_uninstall = [];
688     for i = 1:length (files)
689       tgz = files{i};
690
691       if (exist (tgz, "file"))
692         ## Create a temporary directory.
693         tmpdir = tmpnam ();
694         tmpdirs{end+1} = tmpdir;
695         if (verbose)
696           printf ("mkdir (%s)\n", tmpdir);
697         endif
698         [status, msg] = mkdir (tmpdir);
699         if (status != 1)
700           error ("couldn't create temporary directory: %s", msg);
701         endif
702
703         ## Uncompress the package.
704         if (!exist(tgz, "dir"))
705           if (verbose)
706             printf ("untar (%s, %s)\n", tgz, tmpdir);
707           endif
708           untar (tgz, tmpdir);
709
710           ## Get the name of the directories produced by tar.
711           [dirlist, err, msg] = readdir (tmpdir);
712           if (err)
713             error ("couldn't read directory produced by tar: %s", msg);
714           endif
715
716           if (length (dirlist) > 3)
717             error ("bundles of packages are not allowed");
718           endif
719         else
720           ## we are dealing with a directory, so just copy the files
721           if (verbose)
722             printf ("Copying directory (%s, %s)\n", tgz, tmpdir);
723           endif
724           [status, msg, msgid] = copyfile (tgz, tmpdir);
725           if (!status)
726             disp(msg);
727           endif
728           dirlist = {".", "..", tgz};
729         endif
730       endif
731
732       if (exist (tgz, "file") || exist (tgz, "dir"))
733         ## The two first entries of dirlist are "." and "..".
734         if (exist (tgz, "file"))
735           packdir = fullfile (tmpdir, dirlist{3});
736         else
737           packdir = fullfile (pwd(), dirlist{3});
738         endif
739         packdirs{end+1} = packdir;
740
741         ## Make sure the package contains necessary files.
742         verify_directory (packdir);
743
744         ## Read the DESCRIPTION file.
745         filename = fullfile (packdir, "DESCRIPTION");
746         desc = get_description (filename);
747
748         ## Verify that package name corresponds with filename.
749         [dummy, nm] = fileparts (tgz);
750         if ((length (nm) >= length (desc.name))
751             && ! strcmp (desc.name, nm(1:length(desc.name))))
752           error ("package name '%s' doesn't correspond to its filename '%s'",
753                  desc.name, nm);
754         endif
755
756         ## Set default installation directory.
757         desc.dir = fullfile (prefix, cstrcat (desc.name, "-", desc.version));
758
759         ## Set default architectire dependent installation directory.
760         desc.archprefix = fullfile (archprefix, cstrcat (desc.name, "-",
761                                                          desc.version));
762
763         ## Save desc.
764         descriptions{end+1} = desc;
765
766         ## Are any of the new packages already installed?
767         ## If so we'll remove the old version.
768         for j = 1:length (packages)
769           if (strcmp (packages{j}.name, desc.name))
770             packages_to_uninstall(end+1) = j;
771           endif
772         endfor
773       endif
774     endfor
775   catch
776     ## Something went wrong, delete tmpdirs.
777     for i = 1:length (tmpdirs)
778       rm_rf (tmpdirs{i});
779     endfor
780     rethrow (lasterror ());
781   end_try_catch
782
783   ## Check dependencies.
784   if (handle_deps)
785     ok = true;
786     error_text = "";
787     for i = 1:length (descriptions)
788       desc = descriptions{i};
789       idx2 = setdiff (1:length(descriptions), i);
790       if (global_install)
791         ## Global installation is not allowed to have dependencies on locally
792         ## installed packages.
793         idx1 = setdiff (1:length(global_packages), packages_to_uninstall);
794         pseudo_installed_packages = {global_packages{idx1}, ...
795                                      descriptions{idx2}};
796       else
797         idx1 = setdiff (1:length(local_packages), packages_to_uninstall);
798         pseudo_installed_packages = {local_packages{idx1}, ...
799                                      global_packages{:}, ...
800                                      descriptions{idx2}};
801       endif
802       bad_deps = get_unsatisfied_deps (desc, pseudo_installed_packages);
803       ## Are there any unsatisfied dependencies?
804       if (! isempty (bad_deps))
805         ok = false;
806         for i = 1:length (bad_deps)
807           dep = bad_deps{i};
808           error_text = cstrcat (error_text, " ", desc.name, " needs ",
809                                dep.package, " ", dep.operator, " ",
810                                dep.version, "\n");
811         endfor
812       endif
813     endfor
814
815     ## Did we find any unsatisfied dependencies?
816     if (! ok)
817       error ("the following dependencies where unsatisfied:\n  %s", error_text);
818     endif
819   endif
820
821   ## Prepare each package for installation.
822   try
823     for i = 1:length (descriptions)
824       desc = descriptions{i};
825       pdir = packdirs{i};
826       prepare_installation (desc, pdir);
827       configure_make (desc, pdir, verbose);
828     endfor
829   catch
830     ## Something went wrong, delete tmpdirs.
831     for i = 1:length (tmpdirs)
832       rm_rf (tmpdirs{i});
833     endfor
834     rethrow (lasterror ());
835   end_try_catch
836
837   ## Uninstall the packages that will be replaced.
838   try
839     for i = packages_to_uninstall
840       if (global_install)
841         uninstall ({global_packages{i}.name}, false, verbose, local_list,
842                    global_list, global_install);
843       else
844         uninstall ({local_packages{i}.name}, false, verbose, local_list,
845                    global_list, global_install);
846       endif
847     endfor
848   catch
849     ## Something went wrong, delete tmpdirs.
850     for i = 1:length (tmpdirs)
851       rm_rf (tmpdirs{i});
852     endfor
853     rethrow (lasterror ());
854   end_try_catch
855
856   ## Install each package.
857   try
858     for i = 1:length (descriptions)
859       desc = descriptions{i};
860       pdir = packdirs{i};
861       copy_files (desc, pdir, global_install);
862       create_pkgadddel (desc, pdir, "PKG_ADD", global_install);
863       create_pkgadddel (desc, pdir, "PKG_DEL", global_install);
864       finish_installation (desc, pdir, global_install);
865       generate_lookfor_cache (desc);
866     endfor
867   catch
868     ## Something went wrong, delete tmpdirs.
869     for i = 1:length (tmpdirs)
870       rm_rf (tmpdirs{i});
871     endfor
872     for i = 1:length (descriptions)
873       rm_rf (descriptions{i}.dir);
874       rm_rf (getarchdir (descriptions{i}));
875     endfor
876     rethrow (lasterror ());
877   end_try_catch
878
879   ## Check if the installed directory is empty. If it is remove it
880   ## from the list.
881   for i = length (descriptions):-1:1
882     if (dirempty (descriptions{i}.dir, {"packinfo", "doc"})
883         && dirempty (getarchdir (descriptions{i})))
884       warning ("package %s is empty\n", descriptions{i}.name);
885       rm_rf (descriptions{i}.dir);
886       rm_rf (getarchdir (descriptions{i}));
887       descriptions(i) = [];
888     endif
889   endfor
890
891   ## If the package requested that it is autoloaded, or the installer
892   ## requested that it is, then mark the package as autoloaded.
893   for i = length (descriptions):-1:1
894     if (autoload > 0 || (autoload == 0 && isautoload (descriptions(i))))
895       fclose (fopen (fullfile (descriptions{i}.dir, "packinfo",
896                                ".autoload"), "wt"));
897       descriptions{i}.autoload = 1;
898     endif
899   endfor
900
901   ## Add the packages to the package list.
902   try
903     if (global_install)
904       idx = setdiff (1:length(global_packages), packages_to_uninstall);
905       global_packages = save_order ({global_packages{idx}, descriptions{:}});
906       save (global_list, "global_packages");
907       installed_pkgs_lst = {local_packages{:}, global_packages{:}};
908     else
909       idx = setdiff (1:length(local_packages), packages_to_uninstall);
910       local_packages = save_order ({local_packages{idx}, descriptions{:}});
911       save (local_list, "local_packages");
912       installed_pkgs_lst = {local_packages{:}, global_packages{:}};
913     endif
914   catch
915     ## Something went wrong, delete tmpdirs.
916     for i = 1:length (tmpdirs)
917       rm_rf (tmpdirs{i});
918     endfor
919     for i = 1:length (descriptions)
920       rm_rf (descriptions{i}.dir);
921     endfor
922     if (global_install)
923       printf ("error: couldn't append to %s\n", global_list);
924     else
925       printf ("error: couldn't append to %s\n", local_list);
926     endif
927     rethrow (lasterror ());
928   end_try_catch
929
930   ## All is well, let's clean up.
931   for i = 1:length (tmpdirs)
932     [status, msg] = rm_rf (tmpdirs{i});
933     if (status != 1)
934       warning ("couldn't clean up after my self: %s\n", msg);
935     endif
936   endfor
937
938   ## Add the newly installed packages to the path, so the user
939   ## can begin using them. Only load them if they are marked autoload.
940   if (length (descriptions) > 0)
941     idx = [];
942     for i = 1:length (descriptions)
943       if (isautoload (descriptions(i)))
944         nm = descriptions{i}.name;
945         for j = 1:length (installed_pkgs_lst)
946           if (strcmp (nm, installed_pkgs_lst{j}.name))
947             idx (end + 1) = j;
948             break;
949           endif
950         endfor
951       endif
952     endfor
953     load_packages_and_dependencies (idx, handle_deps, installed_pkgs_lst,
954                                     global_install);
955   endif
956
957   ## If there's a NEWS file, mention it
958   ## we are checking if desc exists too because it's possible to ge to this point
959   ## without creating it such as giving an invalid filename for the package
960   if (exist ("desc", "var") && exist (fullfile (desc.dir, "packinfo", "NEWS"), "file"))
961     printf ("For information about changes from previous versions of the %s package, run 'news (\"%s\")'.\n",
962             desc.name, desc.name);
963   endif
964
965 endfunction
966
967 function uninstall (pkgnames, handle_deps, verbose, local_list,
968                     global_list, global_install)
969   ## Get the list of installed packages.
970   [local_packages, global_packages] = installed_packages(local_list,
971                                                          global_list);
972   if (global_install)
973     installed_pkgs_lst = {local_packages{:}, global_packages{:}};
974   else
975     installed_pkgs_lst = local_packages;
976   endif
977
978   num_packages = length (installed_pkgs_lst);
979   delete_idx = [];
980   for i = 1:num_packages
981     cur_name = installed_pkgs_lst{i}.name;
982     if (any (strcmp (cur_name, pkgnames)))
983       delete_idx(end+1) = i;
984     endif
985   endfor
986
987   ## Are all the packages that should be uninstalled already installed?
988   if (length (delete_idx) != length (pkgnames))
989     if (global_install)
990       ## Try again for a locally installed package.
991       installed_pkgs_lst = local_packages;
992
993       num_packages = length (installed_pkgs_lst);
994       delete_idx = [];
995       for i = 1:num_packages
996         cur_name = installed_pkgs_lst{i}.name;
997         if (any (strcmp (cur_name, pkgnames)))
998           delete_idx(end+1) = i;
999         endif
1000       endfor
1001       if (length (delete_idx) != length (pkgnames))
1002         ## FIXME: We should have a better error message.
1003         warning ("some of the packages you want to uninstall are not installed");
1004       endif
1005     else
1006       ## FIXME: We should have a better error message.
1007       warning ("some of the packages you want to uninstall are not installed");
1008     endif
1009   endif
1010
1011   ## Compute the packages that will remain installed.
1012   idx = setdiff (1:num_packages, delete_idx);
1013   remaining_packages = {installed_pkgs_lst{idx}};
1014
1015   ## Check dependencies.
1016   if (handle_deps)
1017     error_text = "";
1018     for i = 1:length (remaining_packages)
1019       desc = remaining_packages{i};
1020       bad_deps = get_unsatisfied_deps (desc, remaining_packages);
1021
1022       ## Will the uninstallation break any dependencies?
1023       if (! isempty (bad_deps))
1024         for i = 1:length (bad_deps)
1025           dep = bad_deps{i};
1026           error_text = cstrcat (error_text, " ", desc.name, " needs ",
1027                                dep.package, " ", dep.operator, " ",
1028                                dep.version, "\n");
1029         endfor
1030       endif
1031     endfor
1032
1033     if (! isempty (error_text))
1034       error ("the following dependencies where unsatisfied:\n  %s", error_text);
1035     endif
1036   endif
1037
1038   ## Delete the directories containing the packages.
1039   for i = delete_idx
1040     desc = installed_pkgs_lst{i};
1041     ## If an 'on_uninstall.m' exist, call it!
1042     if (exist (fullfile (desc.dir, "packinfo", "on_uninstall.m"), "file"))
1043       wd = pwd ();
1044       cd (fullfile (desc.dir, "packinfo"));
1045       on_uninstall (desc);
1046       cd (wd);
1047     endif
1048     ## Do the actual deletion.
1049     if (desc.loaded)
1050       rmpath (desc.dir);
1051       if (exist (getarchdir (desc)))
1052         rmpath (getarchdir (desc));
1053       endif
1054     endif
1055     if (exist (desc.dir, "dir"))
1056       [status, msg] = rm_rf (desc.dir);
1057       if (status != 1)
1058         error ("couldn't delete directory %s: %s", desc.dir, msg);
1059       endif
1060       [status, msg] = rm_rf (getarchdir (desc));
1061       if (status != 1)
1062         error ("couldn't delete directory %s: %s", getarchdir (desc), msg);
1063       endif
1064       if (dirempty (desc.archprefix))
1065         rm_rf (desc.archprefix);
1066       endif
1067     else
1068       warning ("directory %s previously lost", desc.dir);
1069     endif
1070   endfor
1071
1072   ## Write a new ~/.octave_packages.
1073   if (global_install)
1074     if (length (remaining_packages) == 0)
1075       unlink (global_list);
1076     else
1077       global_packages = save_order (remaining_packages);
1078       save (global_list, "global_packages");
1079     endif
1080   else
1081     if (length (remaining_packages) == 0)
1082       unlink (local_list);
1083     else
1084       local_packages = save_order (remaining_packages);
1085       save (local_list, "local_packages");
1086     endif
1087   endif
1088
1089 endfunction
1090
1091 function [pkg_desc_list, flag] = describe (pkgnames, verbose,
1092                                            local_list, global_list)
1093
1094   ## Get the list of installed packages.
1095   installed_pkgs_lst = installed_packages(local_list, global_list);
1096   num_packages = length (installed_pkgs_lst);
1097
1098
1099   describe_all = false;
1100   if (any (strcmp ("all", pkgnames)))
1101     describe_all = true;
1102     flag(1:num_packages) = {"Not Loaded"};
1103     num_pkgnames = num_packages;
1104   else
1105     num_pkgnames = length (pkgnames);
1106     flag(1:num_pkgnames) = {"Not installed"};
1107   endif
1108
1109   for i = 1:num_packages
1110     curr_name = installed_pkgs_lst{i}.name;
1111     if (describe_all)
1112       name_pos = i;
1113     else
1114       name_pos = find(strcmp (curr_name, pkgnames));
1115     endif
1116
1117     if (! isempty (name_pos))
1118       if (installed_pkgs_lst{i}.loaded)
1119         flag{name_pos} = "Loaded";
1120       else
1121         flag{name_pos} = "Not loaded";
1122       endif
1123
1124       pkg_desc_list{name_pos}.name = installed_pkgs_lst{i}.name;
1125       pkg_desc_list{name_pos}.version = installed_pkgs_lst{i}.version;
1126       pkg_desc_list{name_pos}.description = installed_pkgs_lst{i}.description;
1127       pkg_desc_list{name_pos}.provides = parse_pkg_idx (installed_pkgs_lst{i}.dir);
1128
1129     endif
1130   endfor
1131
1132   non_inst = find (strcmp (flag, "Not installed"));
1133   if (! isempty (non_inst))
1134     if (nargout < 2)
1135       non_inst_str = sprintf (" %s ", pkgnames{non_inst});
1136       error ("some packages are not installed: %s", non_inst_str);
1137     else
1138       pkg_desc_list{non_inst} = struct ("name", {}, "description",
1139                                         {}, "provides", {});
1140     endif
1141   endif
1142
1143   if (nargout == 0)
1144     for i = 1:num_pkgnames
1145       print_package_description (pkg_desc_list{i}.name,
1146                                  pkg_desc_list{i}.version,
1147                                  pkg_desc_list{i}.provides,
1148                                  pkg_desc_list{i}.description,
1149                                  flag{i}, verbose);
1150     endfor
1151   endif
1152
1153 endfunction
1154
1155 ## AUXILIARY FUNCTIONS
1156
1157 ## Read an INDEX file.
1158 function [pkg_idx_struct] = parse_pkg_idx (packdir)
1159
1160   index_file = fullfile (packdir, "packinfo", "INDEX");
1161
1162   if (! exist (index_file, "file"))
1163     error ("could not find any INDEX file in directory %s, try 'pkg rebuild all' to generate missing INDEX files", packdir);
1164   endif
1165
1166
1167   [fid, msg] = fopen (index_file, "r");
1168   if (fid == -1)
1169     error ("the INDEX file %s could not be read: %s",
1170            index_file, msg);
1171   endif
1172
1173   cat_num = 1;
1174   pkg_idx_struct{1}.category = "Uncategorized";
1175   pkg_idx_struct{1}.functions = {};
1176
1177   line = fgetl (fid);
1178   while (isempty (strfind (line, ">>")) && ! feof (fid))
1179     line = fgetl (fid);
1180   endwhile
1181
1182   while (! feof (fid) || line != -1)
1183     if (! any (! isspace (line)) || line(1) == "#" || any (line == "="))
1184       ## Comments,  blank lines or comments about unimplemented
1185       ## functions: do nothing
1186       ## FIXME: probably comments and pointers to external functions
1187       ## could be treated better when printing to screen?
1188     elseif (! isempty (strfind (line, ">>")))
1189       ## Skip package name and description as they are in DESCRIPTION
1190       ## already.
1191     elseif (! isspace (line(1)))
1192       ## Category.
1193       if (! isempty (pkg_idx_struct{cat_num}.functions))
1194         pkg_idx_struct{++cat_num}.functions = {};
1195       endif
1196       pkg_idx_struct{cat_num}.category = deblank (line);
1197     else
1198       ## Function names.
1199       while (any (! isspace (line)))
1200         [fun_name, line] = strtok (line);
1201         pkg_idx_struct{cat_num}.functions{end+1} = deblank (fun_name);
1202       endwhile
1203     endif
1204     line = fgetl (fid);
1205   endwhile
1206   fclose (fid);
1207 endfunction
1208
1209 function print_package_description (pkg_name, pkg_ver, pkg_idx_struct,
1210                                     pkg_desc, status, verbose)
1211
1212   printf ("---\nPackage name:\n\t%s\n", pkg_name);
1213   printf ("Version:\n\t%s\n", pkg_ver);
1214   printf ("Short description:\n\t%s\n", pkg_desc);
1215   printf ("Status:\n\t%s\n", status);
1216   if (verbose)
1217     printf ("---\nProvides:\n");
1218     for i = 1:length(pkg_idx_struct)
1219       if (! isempty (pkg_idx_struct{i}.functions))
1220         printf ("%s\n", pkg_idx_struct{i}.category);
1221         for j = 1:length(pkg_idx_struct{i}.functions)
1222           printf ("\t%s\n", pkg_idx_struct{i}.functions{j});
1223         endfor
1224       endif
1225     endfor
1226   endif
1227
1228 endfunction
1229
1230
1231 function pth = absolute_pathname (pth)
1232   [status, msg, msgid] = fileattrib (pth);
1233   if (status != 1)
1234     error ("could not find the file or path %s", pth);
1235   else
1236     pth = msg.Name;
1237   endif
1238 endfunction
1239
1240 function repackage (builddir, buildlist)
1241   packages = installed_packages (buildlist, buildlist);
1242
1243   wd = pwd();
1244   for i = 1 : length(packages)
1245     pack = packages{i};
1246     unwind_protect
1247       cd (builddir);
1248       mkdir (pack.name);
1249       mkdir (fullfile (pack.name, "inst"));
1250       copyfile (fullfile (pack.dir, "*"), fullfile (pack.name, "inst"));
1251       movefile (fullfile (pack.name, "inst","packinfo", "*"), pack.name);
1252       if (exist (fullfile (pack.name, "inst","packinfo", ".autoload"), "file"))
1253         unlink (fullfile (pack.name, "inst","packinfo", ".autoload"));
1254       endif
1255       rmdir (fullfile (pack.name, "inst", "packinfo"));
1256       if (exist (fullfile (pack.name, "inst", "doc"), "dir"))
1257         movefile (fullfile (pack.name, "inst", "doc"), pack.name);
1258       endif
1259       if (exist (fullfile (pack.name, "inst", "bin"), "dir"))
1260         movefile (fullfile (pack.name, "inst", "bin"), pack.name);
1261       endif
1262       archdir = fullfile (pack.archprefix, cstrcat (pack.name, "-",
1263                           pack.version), getarch ());
1264       if (exist (archdir, "dir"))
1265         if (exist (fullfile (pack.name, "inst", "PKG_ADD"), "file"))
1266           unlink (fullfile (pack.name, "inst", "PKG_ADD"));
1267         endif
1268         if (exist (fullfile (pack.name, "inst", "PKG_DEL"), "file"))
1269           unlink (fullfile (pack.name, "inst", "PKG_DEL"));
1270         endif
1271         if (exist (fullfile (archdir, "PKG_ADD"), "file"))
1272           movefile (fullfile (archdir, "PKG_ADD"),
1273                     fullfile (pack.name, "PKG_ADD"));
1274         endif
1275         if (exist (fullfile (archdir, "PKG_DEL"), "file"))
1276           movefile (fullfile (archdir, "PKG_DEL"),
1277                     fullfile (pack.name, "PKG_DEL"));
1278         endif
1279       else
1280         if (exist (fullfile (pack.name, "inst", "PKG_ADD"), "file"))
1281           movefile (fullfile (pack.name, "inst", "PKG_ADD"),
1282                     fullfile (pack.name, "PKG_ADD"));
1283         endif
1284         if (exist (fullfile (pack.name, "inst", "PKG_DEL"), "file"))
1285           movefile (fullfile (pack.name, "inst", "PKG_DEL"),
1286                     fullfile (pack.name, "PKG_DEL"));
1287         endif
1288       endif
1289       tfile = cstrcat (pack.name, "-", pack.version, ".tar");
1290       tar (tfile, pack.name);
1291       try
1292         gzip (tfile);
1293         unlink (tfile);
1294       catch
1295         warning ("failed to compress %s", tfile);
1296       end_try_catch
1297     unwind_protect_cleanup
1298       if (exist (pack.name, "dir"))
1299         rm_rf (pack.name);
1300       endif
1301       cd (wd);
1302     end_unwind_protect
1303   endfor
1304 endfunction
1305
1306 function auto = isautoload (desc)
1307   auto = false;
1308   if (isfield (desc{1}, "autoload"))
1309     a = desc{1}.autoload;
1310     if ((isnumeric (a) && a > 0)
1311         || (ischar (a) && (strcmpi (a, "true")
1312                          || strcmpi (a, "on")
1313                          || strcmpi (a, "yes")
1314                          || strcmpi (a, "1"))))
1315       auto = true;
1316     endif
1317   endif
1318 endfunction
1319
1320 function prepare_installation (desc, packdir)
1321   ## Is there a pre_install to call?
1322   if (exist (fullfile (packdir, "pre_install.m"), "file"))
1323     wd = pwd ();
1324     try
1325       cd (packdir);
1326       pre_install (desc);
1327       cd (wd);
1328     catch
1329       cd (wd);
1330       rethrow (lasterror ());
1331     end_try_catch
1332   endif
1333
1334   ## If the directory "inst" doesn't exist, we create it.
1335   inst_dir = fullfile (packdir, "inst");
1336   if (! exist (inst_dir, "dir"))
1337     [status, msg] = mkdir (inst_dir);
1338     if (status != 1)
1339       rm_rf (desc.dir);
1340       error ("the 'inst' directory did not exist and could not be created: %s",
1341              msg);
1342     endif
1343   endif
1344 endfunction
1345
1346 function configure_make (desc, packdir, verbose)
1347   ## Perform ./configure, make, make install in "src".
1348   if (exist (fullfile (packdir, "src"), "dir"))
1349     src = fullfile (packdir, "src");
1350     octave_bindir = octave_config_info ("bindir");
1351     mkoctfile = fullfile (octave_bindir, "mkoctfile");
1352     octave_config = fullfile (octave_bindir, "octave-config");
1353     octave_binary = fullfile (octave_bindir, "octave");
1354     cenv = {"MKOCTFILE"; mkoctfile;
1355             "OCTAVE_CONFIG"; octave_config;
1356             "OCTAVE"; octave_binary;
1357             "INSTALLDIR"; desc.dir};
1358     scenv = sprintf ("%s=\"%s\" ", cenv{:});
1359     ## Configure.
1360     if (exist (fullfile (src, "configure"), "file"))
1361       flags = "";
1362       if (isempty (getenv ("CC")))
1363         flags = cstrcat (flags, " CC=\"", octave_config_info ("CC"), "\"");
1364       endif
1365       if (isempty (getenv ("CXX")))
1366         flags = cstrcat (flags, " CXX=\"", octave_config_info ("CXX"), "\"");
1367       endif
1368       if (isempty (getenv ("AR")))
1369         flags = cstrcat (flags, " AR=\"", octave_config_info ("AR"), "\"");
1370       endif
1371       if (isempty (getenv ("RANLIB")))
1372         flags = cstrcat (flags, " RANLIB=\"", octave_config_info ("RANLIB"), "\"");
1373       endif
1374       [status, output] = shell (cstrcat ("cd '", src, "'; ", scenv,
1375                                          "./configure --prefix=\"",
1376                                          desc.dir, "\"", flags));
1377       if (status != 0)
1378         rm_rf (desc.dir);
1379         error ("the configure script returned the following error: %s", output);
1380       elseif (verbose)
1381         printf("%s", output);
1382       endif
1383
1384     endif
1385
1386     ## Make.
1387     if (exist (fullfile (src, "Makefile"), "file"))
1388       [status, output] = shell (cstrcat (scenv, "make -C '", src, "'"));
1389       if (status != 0)
1390         rm_rf (desc.dir);
1391         error ("'make' returned the following error: %s", output);
1392       elseif (verbose)
1393         printf("%s", output);
1394       endif
1395     endif
1396
1397     ## Copy files to "inst" and "inst/arch" (this is instead of 'make
1398     ## install').
1399     files = fullfile (src, "FILES");
1400     instdir = fullfile (packdir, "inst");
1401     archdir = fullfile (packdir, "inst", getarch ());
1402
1403     ## Get file names.
1404     if (exist (files, "file"))
1405       [fid, msg] = fopen (files, "r");
1406       if (fid < 0)
1407         error ("couldn't open %s: %s", files, msg);
1408       endif
1409       filenames = char (fread (fid))';
1410       fclose (fid);
1411       if (filenames(end) == "\n")
1412         filenames(end) = [];
1413       endif
1414       filenames = split_by (filenames, "\n");
1415       delete_idx =  [];
1416       for i = 1:length (filenames)
1417         if (! all (isspace (filenames{i})))
1418           filenames{i} = fullfile (src, filenames{i});
1419         else
1420           delete_idx(end+1) = i;
1421         endif
1422       endfor
1423       filenames(delete_idx) = [];
1424     else
1425       m = dir (fullfile (src, "*.m"));
1426       oct = dir (fullfile (src, "*.oct"));
1427       mex = dir (fullfile (src, "*.mex"));
1428
1429       filenames = cellfun (@(x) fullfile (src, x),
1430                            {m.name, oct.name, mex.name},
1431                            "uniformoutput", false);
1432     endif
1433
1434     ## Split into architecture dependent and independent files.
1435     if (isempty (filenames))
1436       idx = [];
1437     else
1438       idx = cellfun ("is_architecture_dependent", filenames);
1439     endif
1440     archdependent = filenames (idx);
1441     archindependent = filenames (!idx);
1442
1443     ## Copy the files.
1444     if (! all (isspace ([filenames{:}])))
1445         if (! exist (instdir, "dir"))
1446           mkdir (instdir);
1447         endif
1448         if (! all (isspace ([archindependent{:}])))
1449           if (verbose)
1450             printf ("copyfile");
1451             printf (" %s", archindependent{:});
1452             printf ("%s\n", instdir);
1453           endif
1454           [status, output] = copyfile (archindependent, instdir);
1455           if (status != 1)
1456             rm_rf (desc.dir);
1457             error ("Couldn't copy files from 'src' to 'inst': %s", output);
1458           endif
1459         endif
1460         if (! all (isspace ([archdependent{:}])))
1461           if (verbose)
1462             printf ("copyfile");
1463             printf (" %s", archdependent{:});
1464             printf (" %s\n", archdir);
1465           endif
1466           if (! exist (archdir, "dir"))
1467             mkdir (archdir);
1468           endif
1469           [status, output] = copyfile (archdependent, archdir);
1470           if (status != 1)
1471             rm_rf (desc.dir);
1472             error ("Couldn't copy files from 'src' to 'inst': %s", output);
1473           endif
1474         endif
1475     endif
1476   endif
1477 endfunction
1478
1479 function pkg = extract_pkg (nm, pat)
1480   fid = fopen (nm, "rt");
1481   pkg = "";
1482   if (fid >= 0)
1483     while (! feof (fid))
1484       ln = fgetl (fid);
1485       if (ln > 0)
1486         t = regexp (ln, pat, "tokens");
1487         if (! isempty (t))
1488           pkg = cstrcat (pkg, "\n", t{1}{1});
1489         endif
1490       endif
1491     endwhile
1492     if (! isempty (pkg))
1493       pkg = cstrcat (pkg, "\n");
1494     endif
1495     fclose (fid);
1496   endif
1497 endfunction
1498
1499 function create_pkgadddel (desc, packdir, nm, global_install)
1500   instpkg = fullfile (desc.dir, nm);
1501   instfid = fopen (instpkg, "wt");
1502   ## If it is exists, most of the  PKG_* file should go into the
1503   ## architecture dependent directory so that the autoload/mfilename
1504   ## commands work as expected. The only part that doesn't is the
1505   ## part in the main directory.
1506   archdir = fullfile (getarchprefix (desc), cstrcat (desc.name, "-",
1507                       desc.version), getarch ());
1508   if (exist (getarchdir (desc, global_install), "dir"))
1509     archpkg = fullfile (getarchdir (desc, global_install), nm);
1510     archfid = fopen (archpkg, "at");
1511   else
1512     archpkg = instpkg;
1513     archfid = instfid;
1514   endif
1515
1516   if (archfid >= 0 && instfid >= 0)
1517     ## Search all dot-m files for PKG commands.
1518     lst = dir (fullfile (packdir, "inst", "*.m"));
1519     for i = 1:length (lst)
1520       nam = fullfile (packdir, "inst", lst(i).name);
1521       fwrite (instfid, extract_pkg (nam, ['^[#%][#%]* *' nm ': *(.*)$']));
1522     endfor
1523
1524     ## Search all C++ source files for PKG commands.
1525     lst = dir (fullfile (packdir, "src", "*.cc"));
1526     for i = 1:length (lst)
1527       nam = fullfile (packdir, "src", lst(i).name);
1528       fwrite (archfid, extract_pkg (nam, ['^//* *' nm ': *(.*)$']));
1529       fwrite (archfid, extract_pkg (nam, ['^/\** *' nm ': *(.*) *\*/$']));
1530     endfor
1531
1532     ## Add developer included PKG commands.
1533     packdirnm = fullfile (packdir, nm);
1534     if (exist (packdirnm, "file"))
1535       fid = fopen (packdirnm, "rt");
1536       if (fid >= 0)
1537         while (! feof (fid))
1538           ln = fgets (fid);
1539           if (ln > 0)
1540             fwrite (archfid, ln);
1541           endif
1542         endwhile
1543         fclose (fid);
1544       endif
1545     endif
1546
1547     ## If the files is empty remove it.
1548     fclose (instfid);
1549     t = dir (instpkg);
1550     if (t.bytes <= 0)
1551       unlink (instpkg);
1552     endif
1553
1554     if (instfid != archfid)
1555       fclose (archfid);
1556       t = dir (archpkg);
1557       if (t.bytes <= 0)
1558         unlink (archpkg);
1559       endif
1560     endif
1561   endif
1562 endfunction
1563
1564 function copy_files (desc, packdir, global_install)
1565   ## Create the installation directory.
1566   if (! exist (desc.dir, "dir"))
1567     [status, output] = mkdir (desc.dir);
1568     if (status != 1)
1569       error ("couldn't create installation directory %s : %s",
1570       desc.dir, output);
1571     endif
1572   endif
1573
1574   octfiledir = getarchdir (desc);
1575
1576   ## Copy the files from "inst" to installdir.
1577   instdir = fullfile (packdir, "inst");
1578   if (! dirempty (instdir))
1579     [status, output] = copyfile (fullfile (instdir, "*"), desc.dir);
1580     if (status != 1)
1581       rm_rf (desc.dir);
1582       error ("couldn't copy files to the installation directory");
1583     endif
1584     if (exist (fullfile (desc.dir, getarch ()), "dir")
1585         && ! strcmp (fullfile (desc.dir, getarch ()), octfiledir))
1586       if (! exist (octfiledir, "dir"))
1587         ## Can be required to create upto three levels of dirs.
1588         octm1 = fileparts (octfiledir);
1589         if (! exist (octm1, "dir"))
1590           octm2 = fileparts (octm1);
1591           if (! exist (octm2, "dir"))
1592             octm3 = fileparts (octm2);
1593             if (! exist (octm3, "dir"))
1594               [status, output] = mkdir (octm3);
1595               if (status != 1)
1596                 rm_rf (desc.dir);
1597                 error ("couldn't create installation directory %s : %s",
1598                        octm3, output);
1599               endif
1600             endif
1601             [status, output] = mkdir (octm2);
1602             if (status != 1)
1603               rm_rf (desc.dir);
1604               error ("couldn't create installation directory %s : %s",
1605                      octm2, output);
1606             endif
1607           endif
1608           [status, output] = mkdir (octm1);
1609           if (status != 1)
1610             rm_rf (desc.dir);
1611             error ("couldn't create installation directory %s : %s",
1612                    octm1, output);
1613           endif
1614         endif
1615         [status, output] = mkdir (octfiledir);
1616         if (status != 1)
1617           rm_rf (desc.dir);
1618           error ("couldn't create installation directory %s : %s",
1619           octfiledir, output);
1620         endif
1621       endif
1622       [status, output] = movefile (fullfile (desc.dir, getarch (), "*"),
1623                                    octfiledir);
1624       rm_rf (fullfile (desc.dir, getarch ()));
1625
1626       if (status != 1)
1627         rm_rf (desc.dir);
1628         rm_rf (octfiledir);
1629         error ("couldn't copy files to the installation directory");
1630       endif
1631     endif
1632
1633   endif
1634
1635   ## Create the "packinfo" directory.
1636   packinfo = fullfile (desc.dir, "packinfo");
1637   [status, msg] = mkdir (packinfo);
1638   if (status != 1)
1639     rm_rf (desc.dir);
1640     rm_rf (octfiledir);
1641     error ("couldn't create packinfo directory: %s", msg);
1642   endif
1643
1644   packinfo_copy_file ("DESCRIPTION", "required", packdir, packinfo, desc, octfiledir);
1645   packinfo_copy_file ("COPYING", "required", packdir, packinfo, desc, octfiledir);
1646
1647   packinfo_copy_file ("NEWS", "optional", packdir, packinfo, desc, octfiledir);
1648   packinfo_copy_file ("ONEWS", "optional", packdir, packinfo, desc, octfiledir);
1649   packinfo_copy_file ("ChangeLog", "optional", packdir, packinfo, desc, octfiledir);
1650
1651   ## Is there an INDEX file to copy or should we generate one?
1652   index_file = fullfile (packdir, "INDEX");
1653   if (exist(index_file, "file"))
1654     packinfo_copy_file ("INDEX", "required", packdir, packinfo, desc, octfiledir);
1655   else
1656     try
1657       write_index (desc, fullfile (packdir, "inst"),
1658                    fullfile (packinfo, "INDEX"), global_install);
1659     catch
1660       rm_rf (desc.dir);
1661       rm_rf (octfiledir);
1662       rethrow (lasterror ());
1663     end_try_catch
1664   endif
1665
1666   ## Is there an 'on_uninstall.m' to install?
1667   packinfo_copy_file ("on_uninstall.m", "optional", packdir, packinfo, desc, octfiledir);
1668
1669   ## Is there a doc/ directory that needs to be installed?
1670   docdir = fullfile (packdir, "doc");
1671   if (exist (docdir, "dir") && ! dirempty (docdir))
1672     [status, output] = copyfile (docdir, desc.dir);
1673   endif
1674
1675   ## Is there a bin/ directory that needs to be installed?
1676   ## FIXME: Need to treat architecture dependent files in bin/
1677   bindir = fullfile (packdir, "bin");
1678   if (exist (bindir, "dir") && ! dirempty (bindir))
1679     [status, output] = copyfile (bindir, desc.dir);
1680   endif
1681 endfunction
1682
1683 function packinfo_copy_file (filename, requirement, packdir, packinfo, desc, octfiledir)
1684   filepath = fullfile (packdir, filename);
1685   if (!exist (filepath, "file") && strcmpi (requirement, "optional"))
1686     ## do nothing, it's still OK
1687   else
1688     [status, output] = copyfile (filepath, packinfo);
1689     if (status != 1)
1690       rm_rf (desc.dir);
1691       rm_rf (octfiledir);
1692       error ("Couldn't copy %s file: %s", filename, output);
1693     endif
1694   endif
1695 endfunction
1696
1697 function finish_installation (desc, packdir, global_install)
1698   ## Is there a post-install to call?
1699   if (exist (fullfile (packdir, "post_install.m"), "file"))
1700     wd = pwd ();
1701     try
1702       cd (packdir);
1703       post_install (desc);
1704       cd (wd);
1705     catch
1706       cd (wd);
1707       rm_rf (desc.dir);
1708       rm_rf (getarchdir (desc), global_install);
1709       rethrow (lasterror ());
1710     end_try_catch
1711   endif
1712 endfunction
1713
1714 function generate_lookfor_cache (desc)
1715   dirs = split_by (genpath (desc.dir), pathsep ());
1716   for i = 1 : length (dirs)
1717     gen_doc_cache (fullfile (dirs{i}, "doc-cache"), dirs{i});
1718   endfor
1719 endfunction
1720
1721 ## Make sure the package contains the essential files.
1722 function verify_directory (dir)
1723   needed_files = {"COPYING", "DESCRIPTION"};
1724   for f = needed_files
1725     if (! exist (fullfile (dir, f{1}), "file"))
1726       error ("package is missing file: %s", f{1});
1727     endif
1728   endfor
1729 endfunction
1730
1731 ## Parse the DESCRIPTION file.
1732 function desc = get_description (filename)
1733   [fid, msg] = fopen (filename, "r");
1734   if (fid == -1)
1735     error ("the DESCRIPTION file %s could not be read: %s", filename, msg);
1736   endif
1737
1738   desc = struct ();
1739
1740   line = fgetl (fid);
1741   while (line != -1)
1742     if (line(1) == "#")
1743       ## Comments, do nothing.
1744     elseif (isspace(line(1)))
1745       ## Continuation lines
1746       if (exist ("keyword", "var") && isfield (desc, keyword))
1747         desc.(keyword) = cstrcat (desc.(keyword), " ", rstrip(line));
1748       endif
1749     else
1750       ## Keyword/value pair
1751       colon = find (line == ":");
1752       if (length (colon) == 0)
1753         disp ("skipping line");
1754       else
1755         colon = colon(1);
1756         keyword = tolower (strip (line(1:colon-1)));
1757         value = strip (line (colon+1:end));
1758         if (length (value) == 0)
1759             fclose (fid);
1760             error ("The keyword `%s' of the package `%s' has an empty value",
1761                     keyword, desc.name);
1762         endif
1763         desc.(keyword) = value;
1764       endif
1765     endif
1766     line = fgetl (fid);
1767   endwhile
1768   fclose (fid);
1769
1770   ## Make sure all is okay.
1771   needed_fields = {"name", "version", "date", "title", ...
1772                    "author", "maintainer", "description"};
1773   for f = needed_fields
1774     if (! isfield (desc, f{1}))
1775       error ("description is missing needed field %s", f{1});
1776     endif
1777   endfor
1778   desc.version = fix_version (desc.version);
1779   if (isfield (desc, "depends"))
1780     desc.depends = fix_depends (desc.depends);
1781   else
1782     desc.depends = "";
1783   endif
1784   desc.name = tolower (desc.name);
1785 endfunction
1786
1787 ## Make sure the version string v is a valid x.y.z version string
1788 ## Examples: "0.1" => "0.1.0", "monkey" => error(...).
1789 function out = fix_version (v)
1790   dots = find (v == ".");
1791   if (length (dots) == 1)
1792     major = str2num (v(1:dots-1));
1793     minor = str2num (v(dots+1:end));
1794     if (length (major) != 0 && length (minor) != 0)
1795       out = sprintf ("%d.%d.0", major, minor);
1796       return;
1797     endif
1798   elseif (length (dots) == 2)
1799     major = str2num (v(1:dots(1)-1));
1800     minor = str2num (v(dots(1)+1:dots(2)-1));
1801     rev = str2num (v(dots(2)+1:end));
1802     if (length (major) != 0 && length (minor) != 0 && length (rev) != 0)
1803       out = sprintf ("%d.%d.%d", major, minor, rev);
1804       return;
1805     endif
1806   endif
1807   error ("bad version string: %s", v);
1808 endfunction
1809
1810 ## Make sure the depends field is of the right format.
1811 ## This function returns a cell of structures with the following fields:
1812 ##   package, version, operator
1813 function deps_cell = fix_depends (depends)
1814   deps = split_by (tolower (depends), ",");
1815   deps_cell = cell (1, length (deps));
1816
1817   ## For each dependency.
1818   for i = 1:length (deps)
1819     dep = deps{i};
1820     lpar = find (dep == "(");
1821     rpar = find (dep == ")");
1822     ## Does the dependency specify a version
1823     ## Example: package(>= version).
1824     if (length (lpar) == 1 && length (rpar) == 1)
1825       package = tolower (strip (dep(1:lpar-1)));
1826       sub = dep(lpar(1)+1:rpar(1)-1);
1827       parts = strsplit (sub, " ", true);
1828       if (length (parts) != 2)
1829         error ("incorrect syntax for dependency `%s' in the DESCRIPTION file\n",
1830                dep);
1831       endif
1832       operator = parts{1};
1833       if (! any (strcmp (operator, {">", ">=", "<=", "<", "=="})))
1834         error ("unsupported operator: %s", operator);
1835       endif
1836       version  = fix_version (parts{2});
1837
1838   ## If no version is specified for the dependency
1839   ## we say that the version should be greater than
1840   ## or equal to "0.0.0".
1841   else
1842     package = tolower (strip (dep));
1843     operator = ">=";
1844     version  = "0.0.0";
1845   endif
1846   deps_cell{i} = struct ("package", package, "operator", operator,
1847                          "version", version);
1848   endfor
1849 endfunction
1850
1851 ## Strip the text of spaces from the right
1852 ## Example: "  hello world  " => "  hello world"
1853 ## FIXME -- is this the same as deblank?
1854 function text = rstrip (text)
1855   chars = find (! isspace (text));
1856   if (length (chars) > 0)
1857     ## FIXME: shouldn't it be text = text(1:chars(end));
1858     text = text (chars(1):end);
1859   else
1860     text = "";
1861   endif
1862 endfunction
1863
1864 ## Strip the text of spaces from the left and the right.
1865 ## Example: "  hello world  " => "hello world"
1866 function text = strip (text)
1867   chars = find (! isspace (text));
1868   if (length (chars) > 0)
1869     text = text(chars(1):chars(end));
1870   else
1871     text = "";
1872   endif
1873 endfunction
1874
1875 ## Split the text into a cell array of strings by sep.
1876 ## Example: "A, B" => {"A", "B"} (with sep = ",")
1877 function out = split_by (text, sep)
1878   out = strtrim (strsplit (text, sep));
1879 endfunction
1880
1881 ## Create an INDEX file for a package that doesn't provide one.
1882 ##   'desc'  describes the package.
1883 ##   'dir'   is the 'inst' directory in temporary directory.
1884 ##   'index_file' is the name (including path) of resulting INDEX file.
1885 function write_index (desc, dir, index_file, global_install)
1886   ## Get names of functions in dir
1887   [files, err, msg] = readdir (dir);
1888   if (err)
1889     error ("couldn't read directory %s: %s", dir, msg);
1890   endif
1891
1892   ## Get classes in dir
1893   class_idx = strmatch ("@", files);
1894   for k = 1:length (class_idx)
1895     class_name = files {class_idx (k)};
1896     class_dir = fullfile (dir, class_name);
1897     if (exist (class_dir, "dir"))
1898       [files2, err, msg] = readdir (class_dir);
1899       if (err)
1900         error ("couldn't read directory %s: %s", class_dir, msg);
1901       endif
1902       files2 = strcat (class_name, filesep (), files2);
1903       files = [files; files2];
1904     endif
1905   endfor
1906
1907   ## Check for architecture dependent files.
1908   tmpdir = getarchdir (desc);
1909   if (exist (tmpdir, "dir"))
1910     [files2, err, msg] = readdir (tmpdir);
1911     if (err)
1912       error ("couldn't read directory %s: %s", tmpdir, msg);
1913     endif
1914     files = [files; files2];
1915   endif
1916
1917   functions = {};
1918   for i = 1:length (files)
1919     file = files{i};
1920     lf = length (file);
1921     if (lf > 2 && strcmp (file(end-1:end), ".m"))
1922       functions{end+1} = file(1:end-2);
1923     elseif (lf > 4 && strcmp (file(end-3:end), ".oct"))
1924       functions{end+1} = file(1:end-4);
1925     endif
1926   endfor
1927
1928   ## Does desc have a categories field?
1929   if (! isfield (desc, "categories"))
1930     error ("the DESCRIPTION file must have a Categories field, when no INDEX file is given");
1931   endif
1932   categories = split_by (desc.categories, ",");
1933   if (length (categories) < 1)
1934       error ("the Category field is empty");
1935   endif
1936
1937   ## Write INDEX.
1938   fid = fopen (index_file, "w");
1939   if (fid == -1)
1940     error ("couldn't open %s for writing", index_file);
1941   endif
1942   fprintf (fid, "%s >> %s\n", desc.name, desc.title);
1943   fprintf (fid, "%s\n", categories{1});
1944   fprintf (fid, "  %s\n", functions{:});
1945   fclose (fid);
1946 endfunction
1947
1948 function bad_deps = get_unsatisfied_deps (desc, installed_pkgs_lst)
1949   bad_deps = {};
1950
1951   ## For each dependency.
1952   for i = 1:length (desc.depends)
1953     dep = desc.depends{i};
1954
1955     ## Is the current dependency Octave?
1956     if (strcmp (dep.package, "octave"))
1957       if (! compare_versions (OCTAVE_VERSION, dep.version, dep.operator))
1958         bad_deps{end+1} = dep;
1959       endif
1960       ## Is the current dependency not Octave?
1961     else
1962       ok = false;
1963       for i = 1:length (installed_pkgs_lst)
1964         cur_name = installed_pkgs_lst{i}.name;
1965         cur_version = installed_pkgs_lst{i}.version;
1966         if (strcmp (dep.package, cur_name)
1967             && compare_versions (cur_version, dep.version, dep.operator))
1968           ok = true;
1969           break;
1970         endif
1971       endfor
1972       if (! ok)
1973         bad_deps{end+1} = dep;
1974       endif
1975     endif
1976   endfor
1977 endfunction
1978
1979 function [out1, out2] = installed_packages (local_list, global_list)
1980   ## Get the list of installed packages.
1981   try
1982     local_packages = load (local_list).local_packages;
1983   catch
1984     local_packages = {};
1985   end_try_catch
1986   try
1987     global_packages = load (global_list).global_packages;
1988   catch
1989     global_packages = {};
1990   end_try_catch
1991   installed_pkgs_lst = {local_packages{:}, global_packages{:}};
1992
1993   ## Eliminate duplicates in the installed package list.
1994   ## Locally installed packages take precedence.
1995   dup = [];
1996   for i = 1:length (installed_pkgs_lst)
1997     if (find (dup, i))
1998       continue;
1999     endif
2000     for j = (i+1):length (installed_pkgs_lst)
2001       if (find (dup, j))
2002         continue;
2003       endif
2004       if (strcmp (installed_pkgs_lst{i}.name, installed_pkgs_lst{j}.name))
2005         dup = [dup, j];
2006       endif
2007     endfor
2008   endfor
2009   if (! isempty(dup))
2010     installed_pkgs_lst(dup) = [];
2011   endif
2012
2013   ## Now check if the package is loaded.
2014   tmppath = strrep (path(), "\\", "/");
2015   for i = 1:length (installed_pkgs_lst)
2016     if (findstr (tmppath, strrep (installed_pkgs_lst{i}.dir, "\\", "/")))
2017       installed_pkgs_lst{i}.loaded = true;
2018     else
2019       installed_pkgs_lst{i}.loaded = false;
2020     endif
2021   endfor
2022   for i = 1:length (local_packages)
2023     if (findstr (tmppath, strrep (local_packages{i}.dir, "\\", "/")))
2024       local_packages{i}.loaded = true;
2025     else
2026       local_packages{i}.loaded = false;
2027     endif
2028   endfor
2029   for i = 1:length (global_packages)
2030     if (findstr (tmppath, strrep (global_packages{i}.dir, "\\", "/")))
2031       global_packages{i}.loaded = true;
2032     else
2033       global_packages{i}.loaded = false;
2034     endif
2035   endfor
2036
2037   ## Should we return something?
2038   if (nargout == 2)
2039     out1 = local_packages;
2040     out2 = global_packages;
2041     return;
2042   elseif (nargout == 1)
2043     out1 = installed_pkgs_lst;
2044     return;
2045   endif
2046
2047   ## We shouldn't return something, so we'll print something.
2048   num_packages = length (installed_pkgs_lst);
2049   if (num_packages == 0)
2050     printf ("no packages installed.\n");
2051     return;
2052   endif
2053
2054   ## Compute the maximal lengths of name, version, and dir.
2055   h1 = "Package Name";
2056   h2 = "Version";
2057   h3 = "Installation directory";
2058   max_name_length = length (h1);
2059   max_version_length = length (h2);
2060   names = cell (num_packages, 1);
2061   for i = 1:num_packages
2062     max_name_length = max (max_name_length,
2063                            length (installed_pkgs_lst{i}.name));
2064     max_version_length = max (max_version_length,
2065                               length (installed_pkgs_lst{i}.version));
2066     names{i} = installed_pkgs_lst{i}.name;
2067   endfor
2068   max_dir_length = terminal_size()(2) - max_name_length - ...
2069                                              max_version_length - 7;
2070   if (max_dir_length < 20)
2071      max_dir_length = Inf;
2072   endif
2073
2074   h1 = postpad (h1, max_name_length + 1, " ");
2075   h2 = postpad (h2, max_version_length, " ");;
2076
2077   ## Print a header.
2078   header = sprintf("%s | %s | %s\n", h1, h2, h3);
2079   printf (header);
2080   tmp = sprintf (repmat ("-", 1, length(header)-1));
2081   tmp(length(h1)+2) = "+";
2082   tmp(length(h1)+length(h2)+5) = "+";
2083   printf ("%s\n", tmp);
2084
2085   ## Print the packages.
2086   format = sprintf ("%%%ds %%1s| %%%ds | %%s\n", max_name_length,
2087                     max_version_length);
2088   [dummy, idx] = sort (names);
2089   for i = 1:num_packages
2090     cur_name = installed_pkgs_lst{idx(i)}.name;
2091     cur_version = installed_pkgs_lst{idx(i)}.version;
2092     cur_dir = installed_pkgs_lst{idx(i)}.dir;
2093     if (length (cur_dir) > max_dir_length)
2094       first_char = length (cur_dir) - max_dir_length + 4;
2095       first_filesep = strfind (cur_dir(first_char:end), filesep());
2096       if (! isempty (first_filesep))
2097         cur_dir = cstrcat ("...",
2098                           cur_dir((first_char + first_filesep(1) - 1):end));
2099       else
2100         cur_dir = cstrcat ("...", cur_dir(first_char:end));
2101       endif
2102     endif
2103     if (installed_pkgs_lst{idx(i)}.loaded)
2104       cur_loaded = "*";
2105     else
2106       cur_loaded = " ";
2107     endif
2108     printf (format, cur_name, cur_loaded, cur_version, cur_dir);
2109   endfor
2110 endfunction
2111
2112 function load_packages (files, handle_deps, local_list, global_list)
2113   installed_pkgs_lst = installed_packages (local_list, global_list);
2114   num_packages = length (installed_pkgs_lst);
2115
2116   ## Read package names and installdirs into a more convenient format.
2117   pnames = pdirs = cell (1, num_packages);
2118   for i = 1:num_packages
2119     pnames{i} = installed_pkgs_lst{i}.name;
2120     pdirs{i} = installed_pkgs_lst{i}.dir;
2121   endfor
2122
2123   ## Load all.
2124   if (length (files) == 1 && strcmp (files{1}, "all"))
2125     idx = [1:length(installed_pkgs_lst)];
2126   ## Load auto.
2127   elseif (length (files) == 1 && strcmp (files{1}, "auto"))
2128     idx = [];
2129     for i = 1:length (installed_pkgs_lst)
2130       if (exist (fullfile (pdirs{i}, "packinfo", ".autoload"), "file"))
2131         idx (end + 1) = i;
2132       endif
2133     endfor
2134   ## Load package_name1 ...
2135   else
2136     idx = [];
2137     for i = 1:length (files)
2138       idx2 = find (strcmp (pnames, files{i}));
2139       if (! any (idx2))
2140           error ("package %s is not installed", files{i});
2141       endif
2142       idx (end + 1) = idx2;
2143     endfor
2144   endif
2145
2146   ## Load the packages, but take care of the ordering of dependencies.
2147   load_packages_and_dependencies (idx, handle_deps, installed_pkgs_lst, true);
2148 endfunction
2149
2150 function unload_packages (files, handle_deps, local_list, global_list)
2151   installed_pkgs_lst = installed_packages (local_list, global_list);
2152   num_packages = length (installed_pkgs_lst);
2153
2154   ## Read package names and installdirs into a more convenient format.
2155   pnames = pdirs = cell (1, num_packages);
2156   for i = 1:num_packages
2157     pnames{i} = installed_pkgs_lst{i}.name;
2158     pdirs{i} = installed_pkgs_lst{i}.dir;
2159     pdeps{i} = installed_pkgs_lst{i}.depends;
2160   endfor
2161
2162   ## Get the current octave path.
2163   p = split_by (path(), pathsep ());
2164
2165   if (length (files) == 1 && strcmp (files{1}, "all"))
2166     ## Unload all.
2167     dirs = pdirs;
2168     desc = installed_pkgs_lst;
2169   else
2170     ## Unload package_name1 ...
2171     dirs = {};
2172     desc = {};
2173     for i = 1:length (files)
2174       idx = strcmp (pnames, files{i});
2175       if (! any (idx))
2176         error ("package %s is not installed", files{i});
2177       endif
2178         dirs{end+1} = pdirs{idx};
2179         desc{end+1} = installed_pkgs_lst{idx};
2180       endfor
2181   endif
2182
2183   ## Check for architecture dependent directories.
2184   archdirs = {};
2185   for i = 1:length (dirs)
2186     tmpdir = getarchdir (desc{i});
2187     if (exist (tmpdir, "dir"))
2188       archdirs{end+1} = dirs{i};
2189       archdirs{end+1} = tmpdir;
2190     else
2191       archdirs{end+1} = dirs{i};
2192     endif
2193   endfor
2194
2195   ## Unload the packages.
2196   for i = 1:length (archdirs)
2197     d = archdirs{i};
2198     idx = strcmp (p, d);
2199     if (any (idx))
2200       rmpath (d);
2201       ## FIXME: We should also check if we need to remove items from
2202       ## EXEC_PATH.
2203     endif
2204   endfor
2205 endfunction
2206
2207 function [status_out, msg_out] = rm_rf (dir)
2208   if (exist (dir))
2209     crr = confirm_recursive_rmdir (false, "local");
2210     [status, msg] = rmdir (dir, "s");
2211   else
2212     status = 1;
2213     msg = "";
2214   endif
2215   if (nargout > 0)
2216     status_out = status;
2217   endif
2218   if (nargout > 1)
2219     msg_out = msg;
2220   endif
2221 endfunction
2222
2223 function emp = dirempty (nm, ign)
2224   if (exist (nm, "dir"))
2225     if (nargin < 2)
2226       ign = {".", ".."};
2227     else
2228       ign = [{".", ".."}, ign];
2229     endif
2230     l = dir (nm);
2231     for i = 1:length (l)
2232       found = false;
2233       for j = 1:length (ign)
2234         if (strcmp (l(i).name, ign{j}))
2235           found = true;
2236           break;
2237         endif
2238       endfor
2239       if (! found)
2240         emp = false;
2241         return
2242       endif
2243     endfor
2244     emp = true;
2245   else
2246     emp = true;
2247   endif
2248 endfunction
2249
2250 function arch = getarch ()
2251   persistent _arch = cstrcat (octave_config_info ("canonical_host_type"),
2252                               "-", octave_config_info ("api_version"));
2253   arch = _arch;
2254 endfunction
2255
2256 function archprefix = getarchprefix (desc, global_install)
2257   if ((nargin == 2 && global_install) || (nargin < 2 && issuperuser ()))
2258     archprefix = fullfile (octave_config_info ("libdir"), "octave",
2259                            "packages", cstrcat(desc.name, "-", desc.version));
2260   else
2261     archprefix = desc.dir;
2262   endif
2263 endfunction
2264
2265 function archdir = getarchdir (desc)
2266   archdir = fullfile (desc.archprefix, getarch());
2267 endfunction
2268
2269 function s = issuperuser ()
2270   if ((ispc () && ! isunix ()) || (geteuid() == 0))
2271     s = true;
2272   else
2273     s = false;
2274   endif
2275 endfunction
2276
2277 function [status, output] = shell (cmd)
2278   persistent have_sh;
2279
2280   cmd = strrep (cmd, "\\", "/");
2281   if (ispc () && ! isunix ())
2282     if (isempty(have_sh))
2283       if (system("sh.exe -c \"exit\""))
2284         have_sh = false;
2285       else
2286         have_sh = true;
2287       endif
2288     endif
2289     if (have_sh)
2290       [status, output] = system (cstrcat ("sh.exe -c \"", cmd, "\""));
2291     else
2292       error ("Can not find the command shell");
2293     endif
2294   else
2295     [status, output] = system (cmd);
2296   endif
2297 endfunction
2298
2299 function newdesc = save_order (desc)
2300   newdesc = {};
2301   for i = 1 : length(desc)
2302     deps = desc{i}.depends;
2303     if (isempty (deps)
2304         || (length (deps) == 1 && strcmp(deps{1}.package, "octave")))
2305       newdesc {end + 1} = desc{i};
2306     else
2307       tmpdesc = {};
2308       for k = 1 : length (deps)
2309         for j = 1 : length (desc)
2310           if (strcmp (desc{j}.name, deps{k}.package))
2311             tmpdesc{end+1} = desc{j};
2312             break;
2313           endif
2314         endfor
2315       endfor
2316       if (! isempty (tmpdesc))
2317         newdesc = {newdesc{:}, save_order(tmpdesc){:}, desc{i}};
2318       else
2319         newdesc{end+1} = desc{i};
2320       endif
2321     endif
2322   endfor
2323   ## Eliminate the duplicates.
2324   idx = [];
2325   for i = 1 : length (newdesc)
2326     for j = (i + 1) : length (newdesc)
2327       if (strcmp (newdesc{i}.name, newdesc{j}.name))
2328         idx (end + 1) = j;
2329       endif
2330     endfor
2331   endfor
2332   newdesc(idx) = [];
2333 endfunction
2334
2335 function load_packages_and_dependencies (idx, handle_deps, installed_pkgs_lst,
2336                                          global_install)
2337   idx = load_package_dirs (idx, [], handle_deps, installed_pkgs_lst);
2338   dirs = {};
2339   execpath = EXEC_PATH ();
2340   for i = idx;
2341     ndir = installed_pkgs_lst{i}.dir;
2342     dirs{end+1} = ndir;
2343     if (exist (fullfile (dirs{end}, "bin"), "dir"))
2344       execpath = cstrcat (execpath, pathsep (), fullfile (dirs{end}, "bin"));
2345     endif
2346     tmpdir = getarchdir (installed_pkgs_lst{i});
2347     if (exist (tmpdir, "dir"))
2348       dirs{end + 1} = tmpdir;
2349       if (exist (fullfile (dirs{end}, "bin"), "dir"))
2350         execpath = cstrcat (execpath, pathsep (), fullfile (dirs{end}, "bin"));
2351       endif
2352     endif
2353   endfor
2354
2355   ## Load the packages.
2356   if (length (dirs) > 0)
2357     addpath (dirs{:});
2358   endif
2359
2360   ## Add the binaries to exec_path.
2361   if (! strcmp (EXEC_PATH, execpath))
2362     EXEC_PATH (execpath);
2363   endif
2364 endfunction
2365
2366 function idx = load_package_dirs (lidx, idx, handle_deps, installed_pkgs_lst)
2367   for i = lidx
2368     if (isfield (installed_pkgs_lst{i}, "loaded")
2369         && installed_pkgs_lst{i}.loaded)
2370       continue;
2371     else
2372       if (handle_deps)
2373         deps = installed_pkgs_lst{i}.depends;
2374         if ((length (deps) > 1)
2375             || (length (deps) == 1 && ! strcmp(deps{1}.package, "octave")))
2376           tmplidx = [];
2377           for k = 1 : length (deps)
2378             for j = 1 : length (installed_pkgs_lst)
2379               if (strcmp (installed_pkgs_lst{j}.name, deps{k}.package))
2380                 tmplidx (end + 1) = j;
2381                 break;
2382               endif
2383             endfor
2384           endfor
2385           idx = load_package_dirs (tmplidx, idx, handle_deps,
2386                                  installed_pkgs_lst);
2387         endif
2388       endif
2389       if (isempty (find(idx == i)))
2390         idx (end + 1) = i;
2391       endif
2392     endif
2393   endfor
2394 endfunction
2395
2396 function dep = is_architecture_dependent (nm)
2397   persistent archdepsuffix = {".oct",".mex",".a",".lib",".so",".so.*",".dll","dylib"};
2398
2399   dep = false;
2400   for i = 1 : length (archdepsuffix)
2401     ext = archdepsuffix{i};
2402     if (ext(end) == "*")
2403       isglob = true;
2404       ext(end) = [];
2405     else
2406       isglob = false;
2407     endif
2408     pos = findstr (nm, ext);
2409     if (pos)
2410       if (! isglob && (length(nm) - pos(end) != length(ext) - 1))
2411         continue;
2412       endif
2413       dep = true;
2414       break;
2415     endif
2416   endfor
2417 endfunction
2418
2419 function [url, local_file] = get_forge_download (name)
2420   [ver, url] = get_forge_pkg (name);
2421   local_file = [name, "-", ver, ".tar.gz"];
2422 endfunction
2423
2424 function list = list_forge_packages ()
2425   [list, succ] = urlread ("http://octave.sourceforge.net/list_packages.php");
2426   if (succ)
2427     list = strsplit (list, " \n\t", true);
2428   else
2429     error ("pkg: could not read URL, please verify internet connection");
2430   endif
2431   if (nargout == 0)
2432     page_screen_output (false, "local");
2433     puts ("OctaveForge provides these packages:\n");
2434     for i = 1:length (list)
2435       try
2436         ver = get_forge_pkg (list{i});
2437       catch
2438         ver = "unknown";
2439       end_try_catch
2440       printf ("  %s %s\n", list{i}, ver);
2441     endfor
2442   endif
2443 endfunction