<!--  vim: set sw=2 sts=2 et ft=docbk:

  Part of the A-A-P recipe executive: Python functions

  Copyright (C) 2002-2003 Stichting NLnet Labs
  Permission to copy and use this file is specified in the file COPYING.
  If this file is missing you can find it here: http://www.a-a-p.org/COPYING

-->

<para>
  This chapter documents the Aap specific functions that can be used in Python
  code.
</para>

<bridgehead>Python functions grouped by functionality</bridgehead>

<para>
  <informaltable frame='none'>
    <tgroup cols='2'>
      <colspec colwidth="200" colname="c1"/>
      <colspec colname="c2"/>
      <tbody>
        <row>
        <entry namest="c1" nameend="c2">Variable Values</entry>
        <entry></entry>
        </row>
        <row>
        <entry><link linkend="python-expand2dictlist"> expand2dictlist() </link></entry>
        <entry> Expands wildcards and turns it into a list of dictionaries. </entry>
        </row>
        <row>
        <entry><link linkend="python-expand2list"> expand2list() </link></entry>
        <entry> Expands wildcards and turns it into a list of items. </entry>
        </row>
        <row>
        <entry><link linkend="python-expand2string"> expand2string() </link></entry>
        <entry> Expand wildcards, "~user" and "~/user".</entry>
        </row>
        <row>
        <entry><link linkend="python-wildescape"> wildescape() </link></entry>
        <entry> Avoid expansion of wildcard characters. </entry>
        </row>
        <row>
        <entry><link linkend="python-var2dictlist"> var2dictlist() </link></entry>
        <entry> Turns a string into a list of dictionaries. </entry>
        </row>
        <row>
        <entry><link linkend="python-var2list"> var2list() </link></entry>
        <entry>  Turns a string into a list of items. </entry>
        </row>
        <row>
        <entry><link linkend="python-var2string"> var2string() </link></entry>
        <entry>  Does delayed evaluation of "var" when necessary. </entry>
        </row>
        <row>
        <entry><link linkend="python-get-attr"> get_attr() </link></entry>
        <entry>  Returns a dictionary with the attributes of a node. </entry>
        </row>
        <row>
        <entry><link linkend="python-get-var-attr"> get_var_attr() </link></entry>
        <entry>  Returns the value of a specific attribute used in a list of
          items. </entry>
        </row>
        <row>
        <entry>&nbsp;</entry>
        <entry></entry>
        </row>


        <row>
        <entry namest="c1" nameend="c2">Dependencies</entry>
        <entry></entry>
        </row>
        <row>
        <entry><link linkend="python-has-target"> has_target() </link></entry>
        <entry> Checks the kind of dependencies a target has. </entry>
        </row>
        <row>
        <entry><link linkend="python-has-targetarg"> has_targetarg() </link></entry>
        <entry> Checks if one of the arguments was used as an &Aap; argument. </entry>
        </row>
        <row>
        <entry><link linkend="python-has-build-target"> has_build_target() </link></entry>
        <entry> Checks if &Aap; was started that builds something. </entry>
        </row>
        <row>
        <entry><link linkend="python-src2obj"> src2obj() </link></entry>
        <entry> Transform source file names into object file names. </entry>
        </row>
        <row>
        <entry><link linkend="python-skipbuild"> skipbuild() </link></entry>
        <entry>  Returns non-zero when build commands are to be skipped. </entry>
        </row>
        <row>
        <entry>&nbsp;</entry>
        <entry></entry>
        </row>

        <row>
        <entry namest="c1" nameend="c2">Installing</entry>
        <entry></entry>
        </row>
        <row>
        <entry><link linkend="python-ask-prefix"> ask_prefix() </link></entry>
        <entry> Ask the user for an installation prefix. </entry>
        </row>
        <row>
        <entry><link linkend="python-do-bsd-port"> do_BSD_port() </link></entry>
        <entry> Attempt to install a BSD port. </entry>
        </row>
        <row>
        <entry><link linkend="python-do-debian-pkg"> do_Debian_pkg() </link></entry>
        <entry> Attempt to install a Debian package. </entry>
        </row>
        <row>
        <entry><link linkend="python-install-files"> install_files() </link></entry>
        <entry> Install files to a specified directory. </entry>
        </row>
        <row>
        <entry><link linkend="python-uninstall-files"> uninstall_files() </link></entry>
        <entry> Uninstall files from a specified directory. </entry>
        </row>
        <row>
        <entry>&nbsp;</entry>
        <entry></entry>
        </row>

        <row>
        <entry namest="c1" nameend="c2">Filesystem</entry>
        <entry></entry>
        </row>
        <row>
        <entry><link linkend="python-file2string"> file2string() </link></entry>
        <entry> Return the contents of a file as a string. </entry>
        </row>
        <row>
        <entry><link linkend="python-program-path"> program_path() </link></entry>
        <entry> Search for a program and return the full path. </entry>
        </row>
        <row>
        <entry><link linkend="python-tempfname"> tempfname() </link></entry>
        <entry> Returns the name of a temporary file. </entry>
        </row>
        <row>
        <entry><link linkend="python-var-abspath"> var_abspath() </link></entry>
        <entry> Turn filenames into absolute paths. </entry>
        </row>
        <row>
        <entry><link linkend="python-childdir"> childdir() </link></entry>
        <entry> Prepend $CHILDDIR to every item in the argument. </entry>
        </row>
        <row>
        <entry><link linkend="python-parentdir"> parentdir() </link></entry>
        <entry> Prepend $PARENTDIR to every item in the argument. </entry>
        </row>
        <row>
        <entry><link linkend="python-topdir"> topdir() </link></entry>
        <entry> Prepend $TOPDIR to every item in the argument. </entry>
        </row>
        <row>
        <entry><link linkend="python-basedir"> basedir() </link></entry>
        <entry> Prepend $BASEDIR to every item in the argument. </entry>
        </row>
        <row>
        <entry>&nbsp;</entry>
        <entry></entry>
        </row>

        <row>
        <entry namest="c1" nameend="c2">Various</entry>
        <entry></entry>
        </row>
        <row>
        <entry><link linkend="python-aap-has"> aap_has() </link></entry>
        <entry> Check if &Aap; supports a feature. </entry>
        </row>
        <row>
        <entry><link linkend="python-redir-system"> redir_system() </link></entry>
        <entry> Execute a system command are return its stdout. </entry>
        </row>
        <row>
        <entry><link linkend="python-sort-list"> sort_list() </link></entry>
        <entry> Sort a list and return the resulting list. </entry>
        </row>
        <row>
        <entry><link linkend="python-get-html-images"> get_html_images() </link></entry>
        <entry> Extract list of images used in a HTML file. </entry>
        </row>
        <row>
        <entry><link linkend="python-suffix"> suffix() </link></entry>
        <entry> Return the filename suffix. </entry>
        </row>
        <row>
        <entry><link linkend="python-sufreplace"> sufreplace() </link></entry>
        <entry> Replace filename suffix in a list of filenames. </entry>
        </row>
        <row>
        <entry><link linkend="python-sufadd"> sufadd() </link></entry>
        <entry> Add filename suffix in a list of filenames. </entry>
        </row>
        <row>
        <entry><link linkend="python-define-action"> define_action() </link></entry>
        <entry> Define an action. </entry>
        </row>

      </tbody>
    </tgroup>
  </informaltable>
</para>

<bridgehead>Alphabetical list of Python functions</bridgehead>

<para>

<variablelist>

  <varlistentry id='python-aap-has'>
    <term><cmdsynopsis>
      <command>aap_has(name)</command>
    </cmdsynopsis></term>
    <listitem>
      <para>
       Returns non-zero if Aap supports feature "name".  These features can be
       checked:
        <informaltable frame='none'>
          <tgroup cols='2'>
            <colspec colwidth="150"/>
            <tbody>
            <row>
              <entry>: <replaceable>command-name</replaceable></entry>
              <entry>Whether the command "command-name" is supported.</entry>
              </row>
            </tbody>
          </tgroup>
          </informaltable>
            Example:
            </para>
            <para>
            <programlisting>
        @if aap_has(":tree"):
           :tree . {filename = .*\.aap}
              :print recipe found: $name
</programlisting>
            </para>
    </listitem>
  </varlistentry>

  <varlistentry id='python-ask-prefix'>
    <term><cmdsynopsis>
      <command>ask_prefix(name)</command>
    </cmdsynopsis></term>
    <listitem>
      <para>
       Ask the user where to install the package "name".  Returns a tuple
       (asroot, prefix).  "asroot" is a boolean indicating whether the package
       is to be installed as root (using
       <link linkend="cmd-asroot">:asroot</link>).  "prefix" is the root for
       the install.
      </para>
      <para>
       If the user is root it will return (1, "/usr/local/") without asking.
       When aborted it returns an empty prefix.
      </para>
    </listitem>
  </varlistentry>


  <varlistentry id='python-basedir'>
    <term><cmdsynopsis>
      <command>basedir(arg)</command>
    </cmdsynopsis></term>
    <listitem>
      <para>
        Prepend $BASEDIR to every item in "arg". This makes items with a
        path relative to the toplevel recipe relative to the current recipe.
        Example:
        <programlisting>
         LibFiles = `basedir(LibNames)`
</programlisting>
        Also see <link linkend="python-topdir">topdir()</link> and
        <link linkend="python-var-abspath">var_abspath()</link>.
      </para>
    </listitem>
  </varlistentry>


  <varlistentry id='python-childdir'>
    <term><cmdsynopsis>
      <command>childdir(arg)</command>
    </cmdsynopsis></term>
    <listitem>
      <para>
        Prepend $CHILDDIR to every item in "arg". This makes items with a path
        relative to the child recipe relative to the parent recipe.
        Example:
        <programlisting>
         _parent.DISTFILES += `childdir(DISTFILES)`
</programlisting>
        Can only be used in a child recipe.
        Also see <link linkend="python-parentdir">parentdir()</link>,
        <link linkend="python-topdir">topdir()</link> and
        <link linkend="python-var-abspath">var_abspath()</link>.
      </para>
    </listitem>
  </varlistentry>


  <varlistentry id='python-define-action'>
    <term><cmdsynopsis>
        <command>define_action(action, primary, commands, attr = {},
          intypes = [], outtypes = [], defer_var_names = [], outfilename = '')</command>
    </cmdsynopsis></term>
    <listitem>
      <para>
        Define an action with the name "action".
        Also see <xref linkend="specify-actions"/>.
      </para>
      <para>
        The "primary" argument must be zero for a normal action, one for a
        primary action.  A primary action is the preferred way to turn the
        specified input filetypes into the output filetypes.
      </para>
      <para>
        The "commands" argument is a string with the Aap commands that are
        executed for the action.  Normally a multi-line string is used.  Make
        sure the indent of each command is correct!
      </para>
      <para>
        The optional "attr" argument specifies extra attributes for the
        action.
      </para>
      <para>
        The optional "intypes" argument specifies the list of input filetypes.
        When omitted the get_in_types() function must be specified, see below.
      </para>
      <para>
        The optional "outtypes" argument specifies the list of output filetypes.
        When omitted the get_out_types() function must be specified, see below.
      </para>
      <para>
        The optional "defer_var_names" argument specifies a list of variable
        names that are used to make the action invoke another action.  The
        special name "{buildaction}" can be used to check the "buildaction"
        attribute of the source files for a specific build action to be used.
      </para>
      <para>
        For example, if "defer_var_names" is ["BUILD_ACTION", "{buildaction}"]
        then first $BUILD_ACTION is looked at.  If it is defined its value is
        used as the name of the action to be invoked.  If it is not set then
        the "buildaction" attribute of the source files is obtained.
      </para>
      <para>
        In the "commands" argument the $DEFER_ACTION_NAME variable can be
        used, it is set to the found action name.  Otherwise it is empty.
      </para>
      <para>
        The optional "outfilename" argument specifies a string that forms the
        target file name.  It normally includes "$source".  When this argument
        is defined the action can be used in a route with a following action.
        Example: "$(source).c".  The target file name is the source file name
        with ".c" appended.
      </para>
      <para>
        Return Value:
        The define_action() function returns an Action object.  This can be
        used to overrule the get_out_types() and get_in_types() functions.
        These should return a list of the currently supported output and input
        filetypes for the action.  See the "default.aap" recipe for more
        examples.  The defer_action_name() function can also be overruled.  It
        must return the name of an action to defer the work to or None.
        Example:
      </para>
      <programlisting>
          :python
              act = define_action("buildme", 1, """
                        @if DEFER_ACTION_NAME:
                            :do $DEFER_ACTION_NAME {target = $target} $source
                        @else:
                            :sys me &lt; $source &gt; $target
                        """,
                        outtypes = ["me"],
                        intypes = ["moo"])
              def buildme_name(source = ""):
                  name = get_var_attr(source, "buildaction")
                  if name:
                      return name
                  return None
              act.defer_action_name = buildme_name
              def buildme_outtypes(source = "", intype = None):
                  if intype and intype not in self.intypes:
                      return []
                  return ["me"]
</programlisting>
      <para>
        Note that the defer_action_name() function must support an optional
        argument "source", which is a string containing the source files used.
        In the example the "buildaction" attributes of the source files are
        used to find a specific action to be used for building.
      </para>
    </listitem>
  </varlistentry>


  <varlistentry id='python-do-bsd-port'>
    <term><cmdsynopsis>
      <command>do_BSD_port(name, target)</command>
    </cmdsynopsis></term>
    <listitem>
      <para>
        Attempt to install the BSD port "name".  This includes
        the directory in which the port lives, e.g.:
        "devel/templ".
        </para>
        <para>
        The BSD port system will take care of dependencies.
        This may result in many more ports to be installed
        than the one you asked for.
        </para>
        <para>
        "target" is passed to the "make" command for the port.
        When "target" is "all" the port is build but not
        installed.  When "target" is "install" it will be
        build and installed.
        </para>
        <para>
        When needed the user will be asked to enter the root
        password.  The "make" command is run in a separate
        root shell (every command must be confirmed for
        security reasons).
      </para>
      <para>
      Returns non-zero for success.
      </para>
    </listitem>
  </varlistentry>

  <varlistentry id='python-do-debian-pkg'>
    <term><cmdsynopsis>
      <command>do_Debian_pkg(name, target)</command>
    </cmdsynopsis></term>
    <listitem>
      <para>
        Attempt to install the Debian package "name".  This is the name that
        "apt-get" uses.
        </para>
        <para>
          When not on a Debian system or when "apt-get" cannot be found the
          function returns with a zero value.
        </para>
        <para>
        The Debian "apt-get" will take care of dependencies.
        This may result in many more packages to be installed
        than the one you asked for.
        </para>
        <para>
        "target" specifies what to do.  When "target" is "install" the package
        will be installed.
        </para>
        <para>
        When needed the user will be asked to enter the root
        password.  The "make" command is run in a separate
        root shell (every command must be confirmed for
        security reasons).
      </para>
      <para>
      Returns a non-zero number for success.
      </para>
    </listitem>
  </varlistentry>

  <varlistentry id='python-expand2dictlist'>
    <term><cmdsynopsis>
      <command>expand2dictlist(expr)</command>
    </cmdsynopsis></term>
    <listitem>
      <para>
        Turns a variable with a string value into a list of
        dictionaries.  Each dictionary has a "name" entry for
        the item itself and other entries are attributes.
        Wildcards in "expr" are expanded.  See <link
        linkend="python-var2dictlist">var2dictlist()</link>
        for not expanding wildcards.
        Example:
        </para>
        <para>
        <programlisting>
        source = file1 {force} file2 file3
        @for item in expand2dictlist(source):
        @    if item.get("force"):
                 :print forced item: `item["name"]`
</programlisting>
      </para>
    </listitem>
  </varlistentry>

  <varlistentry id='python-expand2list'>
    <term><cmdsynopsis>
      <command>expand2list(expr)</command>
    </cmdsynopsis></term>
    <listitem>
      <para>
        Turns a variable with a string value into a list of
        items.  Attributes are discarded.  Delayed evaluation is
        taken care of.
        </para>
        <para>
        Wildcards in "expr" are expanded.  See <link
        linkend="python-var2list">var2list()</link> for
        not expanding wildcards.
        Example:
        </para>
        <para>
        <programlisting>
         source = file1 file2 file3
         @for fname in expand2list(source):
             :sys prog $fname
</programlisting>
      </para>
    </listitem>
  </varlistentry>

  <varlistentry id='python-expand2string'>
    <term><cmdsynopsis>
      <command>expand2string(expr)</command>
    </cmdsynopsis></term>
    <listitem>
      <para>
        Expand wildcards, "~user" and "~/user" in "expr".
        Returns the expanded string.
        "expr" is handled as a list of items, white space is
        collapsed into a single space.
      </para>
    </listitem>
  </varlistentry>

  <varlistentry id='python-file2string'>
    <term><cmdsynopsis>
      <command>file2string(fname, dict = None)</command>
    </cmdsynopsis></term>
    <listitem>
      <para>
        Reads the file "fname" and concatenates the lines into
        one string.  Lines starting with a '#' are ignored.
        One space is inserted in between joined lines, other
        white space (including CR and VT) at the start and end
        of a line is removed.
        </para>
        <para>
        When "fname" doesn't exist or can't be read an error
        message is given and an empty string is returned.
        &Aap; does continue with the following commands.
        </para>
        <para>
        "dict" is used to obtain the value for $MESSAGE.
        The default is None.  To avoid the error message for a not existing
        file use something like this:
        <programlisting>
        @foofile = file2string("foo", {"MESSAGE" : ""})
</programlisting>
      </para>
    </listitem>
  </varlistentry>

  <varlistentry id='python-get-attr'>
    <term><cmdsynopsis>
      <command>get_attr(name)</command>
    </cmdsynopsis></term>
    <listitem>
      <para>
        Returns a dictionary with the attributes of "name".
        If "name" is unknown or has no attributes, an empty
        dictionary is returned.  Example:
        <programlisting>
        :attr {logical = yes} foobar
        @print "foobar attributes: ", get_attr("foobar")
</programlisting>
      </para>
    </listitem>
  </varlistentry>

  <varlistentry id='python-get-html-images'>
    <term><cmdsynopsis>
      <command>get_html_images(files, add_dir = 1)</command>
    </cmdsynopsis></term>
    <listitem>
      <para>
        Returns a list of the images used in HTML files.
        The argument "files" can be a Python list of file names (e.g., what
        glob() returns) or an &Aap; list of files (white separated).
        Only images with a relative path and no URL are included and
        each name is included only once.
      </para>
      <para>
        Since the image file names are relative to the HTML file name, the
        directory of the HTML file is prepended to the image file name.  If
        this is not wanted set the "add_dir" argument to zero.  The returned
        file names are then as they appear in the HTML files.
      </para>
      <para>
        This function is useful to make a list of image files that needs to be
        uploaded to a web server.  Example:
        <programlisting>
        Files = index.html burp.html contact.html
        Files += `get_html_images(Files)`
</programlisting>
      </para>
      <para>
        Note that this function is not perfect, it only works for relative
        file names, ignores Javascript and PHP, etc.
      </para>
    </listitem>
  </varlistentry>

  <varlistentry id='python-get-var-attr'>
    <term><cmdsynopsis>
      <command>get_var_attr(expr, attr_name)</command>
    </cmdsynopsis></term>
    <listitem>
      <para>
        "expr" is handled as a list of items with attributes.
        For each item the attribute "attr_name" is obtained.  If the item in
        "expr" does not specify an attribute it is obtained from the node
        (attributes previously added with
        <link linkend="cmd-attr">:attr</link>).
        If none of the items has an attribute "attr_name" the function returns
        None.
        if two items have a different value for attribute "attr_name" a
        UserError exception is raised.
        Otherwise the value of attribute "attr_name" is returned.
        Example:
        <programlisting>
          action = `get_var_attr(source, "buildaction")`
          @if action:
              :do $action $source
</programlisting>
      </para>
    </listitem>
  </varlistentry>

  <varlistentry id='python-has-target'>
    <term><cmdsynopsis>
      <command>has_target(target)</command>
    </cmdsynopsis></term>
    <listitem>
      <para>
      Returns a number, depending on whether a dependency exists in which
      "target" is a target item:
        <informaltable frame='none'>
          <tgroup cols='2'>
          <colspec colwidth="050"/>
            <tbody>
              <row>
                <entry>0</entry>
                <entry>there is no dependency for "target"</entry>
              </row>
              <row>
                <entry>1</entry>
                <entry>a dependency for "target" exists, there is no
                dependency with build commands</entry>
              </row>
              <row>
                <entry>2</entry>
                <entry>a dependency for "target" with build commands
                exists</entry>
              </row>
            </tbody>
            </tgroup>
          </informaltable>
             Example:
          </para>
          <para>
          <programlisting>
        @if not has_target("fetch"):
</programlisting>
      </para>
    </listitem>
  </varlistentry>

  <varlistentry id='python-has-targetarg'>
    <term><cmdsynopsis>
      <command>has_targetarg(targets)</command>
    </cmdsynopsis></term>
    <listitem>
      <para>
        Returns non-zero if one of the items in "targets" was used as a build
        target in the aap command.  Example:
        </para>
        <para>
            <programlisting>
        @if has_targetarg("commit tar"):
            :include maintainer.aap
</programlisting>
      </para>
    </listitem>
  </varlistentry>

  <varlistentry id='python-has-build-target'>
    <term><cmdsynopsis>
      <command>has_build_target()</command>
    </cmdsynopsis></term>
    <listitem>
      <para>
        Returns non-zero if Aap was started with a target that will build
        something or no target at all (the default target is expected to build
        something).  Returns zero if the only targets are
        "clean", "cleanmore", "cleanALL" or "fetch".
        </para>
        <para>
        Useful to skip configuration when it's pointless.
      </para>
    </listitem>
  </varlistentry>

  <varlistentry id='python-install-files'>
    <term><cmdsynopsis>
      <command>install_files(dir, sources, mode)</command>
    </cmdsynopsis></term>
    <listitem>
      <para>
        Install the files specified in "sources" in the directory
        "$DESTDIR/$PREFIX/dir".
        Set the file protection to "mode".  Attributes on the items in
        "sources" can change the destination directory and mode, see
        <xref linkend="install-dirs"/>.
      </para>
      <para>
        "dir" can be any directory.  When "dir" is an absolute path (starts
        with a slash) then $PREFIX is not prepended.  $DESTDIR is always
        prepended.
      </para>
      <para>
        Note that only the tails of the filenames in "sources" are used, thus
        installing "foo/bar.txt" into the "/tmp" directory results in
        "/tmp/bar.txt".
      </para>
      <para>
        "mode" is normally a string with octal digits, e.g., "0644".
      </para>
      <para>
        Example:
      </para>
        <programlisting>
          Files = test/foo.txt test/bar.txt
          Dir = /usr/local/share
          ...
          install-local:
             @install_files(_no.Dir, _no.Files, '0644')
</programlisting>
      <para>
        For uninstalling see
        <link linkend="python-uninstall-files">uninstall_files()</link>
      </para>
    </listitem>
  </varlistentry>


  <varlistentry id='python-parentdir'>
    <term><cmdsynopsis>
      <command>parentdir(arg)</command>
    </cmdsynopsis></term>
    <listitem>
      <para>
        Prepend $PARENTDIR to every item in "arg". This makes items with a
        path relative to the parent recipe relative to the current recipe.
        Example:
        <programlisting>
         ImgFiles = `parentdir(ImgNames)`
</programlisting>
        Can only be used in a child recipe.
        Also see <link linkend="python-childdir">childdir()</link> and
        <link linkend="python-var-abspath">var_abspath()</link>.
      </para>
    </listitem>
  </varlistentry>


  <varlistentry id='python-program-path'>
    <term><cmdsynopsis>
      <command>program_path(name, path = None, pathext = None, skip = None)</command>
    </cmdsynopsis></term>
    <listitem>
      <para>
        Returns the path for program "name".  This uses the
        $PATH environment variable or os.defpath if it isn't
        set.
        </para>
        <para>
        Additionally, the directory where &Aap; is installed
        and the "bin" subdirectory are searched.  This finds
        tools supplied with &Aap; and installed packages.
        This is not done when the optional "path" argument is
        supplied.
        </para>
        <para>
        On MS-Windows and OS/2 also checks with extensions
        added.  This uses the $PATHEXT environment variable if
        set (The separator used is ';' if there is one, the
        system-dependent separator otherwise).  Otherwise the
        extnsions ".exe", ".com", ".bat", ".cmd" are used.
        When "name" includes a suffix (a dot in the last
        component) adding extensions is not done.
        </para>
        <para>
        Returns the first program found.
        Returns None when "name" could not be found.
        </para>
        <para>
        Only finds executable files, not ordinary files.
        </para>
        <para>
        Optional arguments:
        <informaltable frame='none'>
          <tgroup cols='2'>
            <colspec colwidth="100"/>
            <tbody>
              <row>
                <entry>path</entry>
                <entry>search path to use instead of $PATH;
                                when a string items are separated with
                                os.pathsep</entry>
              </row>
              <row>
                <entry>pathext</entry>
                <entry>extensions to try.  Can be a list or a string.
                When a string is used items must be separated with
                os.pathsep</entry>
              </row>
              <row>
                <entry>skip</entry>
                <entry>name of directory to skip, "name" is not found in this
                directory</entry>
              </row>
            </tbody>
            </tgroup>
          </informaltable>
        </para>
        <para>
        Example, search for program "foo.py" and "foo.sh":
        </para>
        <para>
        <programlisting>
        p = `program_path("foo", pathext = [ '.py', '.sh' ])`
</programlisting>
      </para>
    </listitem>
  </varlistentry>

  <varlistentry id='python-redir-system'>
    <term><cmdsynopsis>
      <command>redir_system(cmd, use_tee = 1)</command>
    </cmdsynopsis></term>
    <listitem>
      <para>
          Execute shell commands "cmd" and return two items: a
          number indicating success and the stdout.
          </para>
          <para>
          By default "tee" is used to display the
          output as well as redirecting it.  When no output is
          desired set "use_tee" to zero.  Example:
          <programlisting>
        ok, text = redir_system("ls", 0)
        if ok:
             print "ls output: %s" % text
        else:
             print "ls failed"
</programlisting>
      </para>
    </listitem>
  </varlistentry>


  <varlistentry id='python-skipbuild'>
    <term><cmdsynopsis>
      <command>skipbuild()</command>
    </cmdsynopsis></term>
    <listitem>
      <para>
         Returns non-zero when build commands are to be skipped.
         This is when &Aap; was started with the --nobuild or --touch
         argument.
      </para>
    </listitem>
  </varlistentry>


  <varlistentry id='python-sort-list'>
    <term><cmdsynopsis>
      <command>sort_list(list)</command>
    </cmdsynopsis></term>
    <listitem>
      <para>
         sorts a list and returns the list.  Example:
      </para>
      <para>
        <programlisting>
        INP = `sort_list(glob("*.inp"))`
</programlisting>
      </para>
      <para>
        The Python list.sort() method doesn't return the sorted list.
      </para>
    </listitem>
  </varlistentry>

  <varlistentry id='python-src2obj'>
    <term><cmdsynopsis>
      <command>src2obj(source, sufname = "OBJSUF", auto = 1)</command>
    </cmdsynopsis></term>
    <listitem>
      <para>
        Transform a string, which is a list of source files, into the
        corresponding list of object files.  Each item in "source" is changed
        by prepending $BDIR and changing or appending the suffix specified
        with "sufname" (defaults to $OBJSUF).
      </para>
      <para>
        The attribute "var_BDIR" is used instead of $BDIR when the attribute
        exists.  The attribute "suffix" is used for the suffix instead of
        using the "suffix" argument when the attribute exists.
      </para>
      <para>
        When the "auto" argument is non-zero (the default) then the filetype
        of the source file will be prepended to the "sufname" (in upper case
        and adding an underscore).  Thus for a Java source file, $JAVA_OBJSUF
        will be used.  When it does not exists "sufname" is used.  When this
        is not wanted the "auto" argument must be set to zero.
      </para>
    </listitem>
  </varlistentry>


  <varlistentry id='python-suffix'>
    <term><cmdsynopsis>
      <command>suffix(name)</command>
    </cmdsynopsis></term>
    <listitem>
      <para>
        Return the filename suffix. If there isn't one an empty string is
        returned.  Example: suffix("foo.c") returns "c".
        </para>
        <para>
        Note that the dot isn't included, while variables like $OBJSUF do
        include the dot.
        </para>
    </listitem>
  </varlistentry>


  <varlistentry id='python-sufadd'>
    <term><cmdsynopsis>
      <command>sufadd(suf, expr, always = 0)</command>
    </cmdsynopsis></term>
    <listitem>
      <para>
        Returns "expr" with suffix "suf" appended.
        When "always" is non-zero the suffix is also added to items that
        already have a suffix.  If "always" is omitted or zero the suffix is
        only added to items without a suffix.
        "expr" can be a list of filenames.
        Example:
        </para>
        <para>
        <programlisting>
        libs = `sufadd(".lib", libs)`
</programlisting>
        </para>
    </listitem>
  </varlistentry>

  <varlistentry id='python-sufreplace'>
    <term><cmdsynopsis>
      <command>sufreplace(from, to, expr)</command>
    </cmdsynopsis></term>
    <listitem>
      <para>
        Returns "expr" with all occurences of the suffix
        "from" changed to "to".
        When "from" is empty any suffix is changed to "to".
        When "from" is None the suffix "to" is also appended to items that do
        not have a suffix yet.
        "expr" can be a list of filenames.
        Example:
        </para>
        <para>
        <programlisting>
        OBJECT = `sufreplace("", OBJSUF, SOURCE)`
</programlisting>
        </para>
    </listitem>
  </varlistentry>


  <varlistentry id='python-tempfname'>
    <term><cmdsynopsis>
      <command>tempfname()</command>
    </cmdsynopsis></term>
    <listitem>
      <para>
         Returns the name of a file which does not exist and can be used
         temporarily.
         </para>
         <para>
         The recipe should take of deleting the file, but &Aap; may delete the
         directory in which the file resides when it exits.  Thus don't depend
         on the file to continue to exist after &Aap; exits.
      </para>
    </listitem>
  </varlistentry>

  <varlistentry id='python-topdir'>
    <term><cmdsynopsis>
      <command>topdir(arg)</command>
    </cmdsynopsis></term>
    <listitem>
      <para>
         Prepend $TOPDIR to every item in "arg".  This makes items with a path
         relative to the current recipe relative to the toplevel recipe.
         Example:
          </para>
          <programlisting>
        _top.DISTFILES += `topdir(DISTFILES)`
</programlisting>
          <para>
          Also see
          <link linkend="python-childdir">childdir()</link> and
          <link linkend="python-var-abspath">var_abspath()</link>.
      </para>
    </listitem>
  </varlistentry>

  <varlistentry id='python-uninstall-files'>
    <term><cmdsynopsis>
      <command>uninstall_files(dir, sources)</command>
    </cmdsynopsis></term>
    <listitem>
      <para>
        Uninstall the files specified in "sources" from the directory
        "$DESTDIR/$PREFIX/dir".
        When given the same arguments as
        <link linkend="python-install-files">install_files()</link>
        it will delete the installed files.
      </para>
      <para>
        Example:
      </para>
        <programlisting>
          Files = test/foo.txt test/bar.txt
          Dir = /usr/local/share
          ...
          uninstall-local:
             @uninstall_files(_no.Dir, _no.Files)
</programlisting>
    </listitem>
  </varlistentry>

  <varlistentry id='python-var-abspath'>
    <term><cmdsynopsis>
      <command>var_abspath(var)</command>
    </cmdsynopsis></term>
    <listitem>
      <para>
        Returns "var" with all filenames turned into absolute paths.
        Prepends the current directory to each item in "var" which isn't an
        absolute path name.  Example:
        <programlisting>
        :print `var_abspath("foo bar")`
</programlisting>
        Running this in "/home/mool/test" results in:
        <literallayout>        /home/mool/test/foo /home/mool/test/bar </literallayout>
      </para>
    </listitem>
  </varlistentry>


  <varlistentry id='python-var2dictlist'>
    <term><cmdsynopsis>
      <command>var2dictlist(var)</command>
    </cmdsynopsis></term>
    <listitem>
      <para>
       Turns "var" into a list of dictionaries.  "var" must be a string or a
       variable.
        Each dictionary has a "name" entry for
        the item itself and other entries are attributes.
        Example:
        </para>
        <programlisting>
        source = file1 {force} file2 file3
        @for item in var2dictlist(source):
        @    if item.get("force"):
            :print forced item: `item["name"]`
</programlisting>
       <para>
        See <link linkend="python-expand2dictlist">expand2dictlist()</link>
        for expanding wildcards.
      </para>
    </listitem>
  </varlistentry>

  <varlistentry id='python-var2list'>
    <term><cmdsynopsis>
      <command>var2list(var)</command>
    </cmdsynopsis></term>
    <listitem>
      <para>
       Turns "var" into a list of items.  "var" must be a string or a
       variable.
        Attributes are discarded.  Delayed evaluation is
        taken care of.  Example:
        </para>
        <programlisting>
        source = file1 file2 file3
        @for fname in var2list(source):
            :sys prog $fname
</programlisting>
        <para>
        See <link linkend="python-expand2list">expand2list()</link> for
        expanding wildcards.
      </para>
    </listitem>
  </varlistentry>

  <varlistentry id='python-var2string'>
    <term><cmdsynopsis>
      <command>var2string(var)</command>
    </cmdsynopsis></term>
    <listitem>
      <para>
        Does delayed evaluation of "var" when necessary.  Variables that
        should be expanded when used use the ExpandVar class and cannot be
        used directly.  The unexpanded value is accessible with "var.val".
        Illustration:
        <programlisting>
        bar = aaa
        foo $= $bar
        bar = bbb
        :print $$foo: $foo
        :print Unexpanded: `foo.val`
        :print Expanded: `var2string(foo)`
</programlisting>
            Output:
            <literallayout>        $foo: bbb
        Unexpanded: $bar
        Expanded: bbb </literallayout>
      </para>
      <para>
      This also takes care of changing a Python list and other variable types
      to a string.  A None value is turned into an empty string.
      </para>
    </listitem>
  </varlistentry>

  <varlistentry id='python-wildescape'>
    <term><cmdsynopsis>
      <command>wildescape(expr)</command>
    </cmdsynopsis></term>
    <listitem>
      <para>
         Return the string "expr" with wildcard characters
         escaped, so that expanding wildcards will result in
         "expr".  This puts the characters '*', '?' and '['
         inside [].  Example:
          </para>
          <para>
          <programlisting>
                  files = `glob("images/*")`
                  :attr {asdf} `wildescape(files)`
</programlisting>
          </para>
          <para>
          Equivalent to:
          </para>
          <para>
          <programlisting>
                  :attr {asdf} images/*
</programlisting>
      </para>
    </listitem>
  </varlistentry>

</variablelist>
</para>

<para>
While developing &Aap; some functions have been renamed.  The old names are
still available to keep old recipes from working.  But some day these will be
removed.
    <informaltable frame='none'>
      <tgroup cols='2'>
        <colspec colwidth="150"/>
      <thead>
        <row>
        <entry> obsolete name</entry>
        <entry> new name</entry>
        </row>
      </thead>
      <tbody>
        <row>
        <entry> <anchor id="python-aap-sufreplace"/>aap_sufreplace() </entry>
        <entry> sufreplace() </entry>
        </row>
        <row>
        <entry> <anchor id="python-aap-abspath"/>aap_abspath() </entry>
        <entry> var_abspath() </entry>
        </row>
        <row>
        <entry> <anchor id="pytnon-aap-expand"/>aap_expand() </entry>
        <entry> var2string() </entry>
        </row>
        <row>
        <entry> <anchor id="python-expandvar"/>expandvar() </entry>
        <entry> expand2string() </entry>
        </row>
      </tbody>
      </tgroup>
    </informaltable>
</para>
