chiark / gitweb /
Bring CGI docs pretty much up to date
authorRichard Kettlewell <rjk@greenend.org.uk>
Sun, 18 May 2008 18:23:09 +0000 (19:23 +0100)
committerRichard Kettlewell <rjk@greenend.org.uk>
Sun, 18 May 2008 18:23:09 +0000 (19:23 +0100)
14 files changed:
.bzrignore
doc/Makefile.am
doc/disorder.1.in
doc/disorder.cgi.8.in [new file with mode: 0644]
doc/disorder_actions.5.head [new file with mode: 0644]
doc/disorder_actions.5.tail [new file with mode: 0644]
doc/disorder_config.5.in
doc/disorder_options.5.in [new file with mode: 0644]
doc/disorder_templates.5.tail
doc/disorderd.8.in
lib/macros-builtin.c
scripts/macro-docs
server/actions.c
server/macros-disorder.c

index f0f878da1dd483ce505cb3f82e1f74127719c868..c701a861deedd82f353e51cff1ca8897bb3d178e 100644 (file)
@@ -179,3 +179,9 @@ doc/disorder_templates.5
 oc/disorder_templates.5.html
 doc/disorder_templates.5
 doc/disorder_templates.5.html
+doc/disorder.cgi.8
+doc/disorder.cgi.8.html
+doc/disorder_actions.5
+doc/disorder_actions.5.html
+doc/disorder_options.5
+doc/disorder_options.5.html
index c2971bbea3f251e32234af3c8c135aafa899fec4..cff3570874031b0d90f87c8add7764c22047a03f 100644 (file)
@@ -24,13 +24,15 @@ man_MANS=disorderd.8 disorder.1 disorder.3 disorder_config.5 disorder-dump.8 \
        disorder_protocol.5 disorder-deadlock.8 \
        disorder-rescan.8 disobedience.1 disorderfm.1 disorder-speaker.8 \
        disorder-playrtp.1 disorder-normalize.8 disorder-decode.8 \
-       disorder-stats.8 disorder-dbupgrade.8 disorder_templates.5
+       disorder-stats.8 disorder-dbupgrade.8 disorder_templates.5 \
+       disorder_actions.5 disorder_options.5 disorder.cgi.8
 noinst_MANS=tkdisorder.1
 
 SEDFILES=disorder.1 disorderd.8 disorder_config.5 \
        disorder-dump.8 disorder_protocol.5 disorder-deadlock.8 \
        disorder-rescan.8 disobedience.1 disorderfm.1 disorder-playrtp.1 \
-       disorder-decode.8 disorder-stats.8 disorder-dbupgrade.8
+       disorder-decode.8 disorder-stats.8 disorder-dbupgrade.8 \
+       disorder_options.5 disorder.cgi.8
 
 include ${top_srcdir}/scripts/sedfiles.make
 
@@ -60,12 +62,26 @@ disorder_templates.5: disorder_templates.5.head disorder_templates.5.tail \
        cat ${srcdir}/disorder_templates.5.tail >> disorder_templates.5.new
        mv disorder_templates.5.new disorder_templates.5
 
+disorder_actions.5: disorder_actions.5.head disorder_actions.5.tail \
+               $(top_srcdir)/lib/macros-builtin.c \
+               $(top_srcdir)/server/actions.c \
+               $(top_srcdir)/scripts/macro-docs
+       rm -f disorder_actions.5.new
+       cat ${srcdir}/disorder_actions.5.head >> disorder_actions.5.new
+       $(top_srcdir)/scripts/macro-docs >> disorder_actions.5.new \
+               $(top_srcdir)/server/actions.c 
+       cat ${srcdir}/disorder_actions.5.tail >> disorder_actions.5.new
+       mv disorder_actions.5.new disorder_actions.5
+
 EXTRA_DIST=disorderd.8.in disorder.1.in disorder_config.5.in \
           disorder.3 disorder-dump.8.in disorder_protocol.5.in \
           tkdisorder.1 disorder-deadlock.8.in disorder-rescan.8.in \
           disobedience.1.in disorderfm.1.in disorder-speaker.8 \
           disorder-playrtp.1.in disorder-decode.8.in disorder-normalize.8 \
-          disorder-stats.8.in disorder-dbupgrade.8.in
+          disorder-stats.8.in disorder-dbupgrade.8.in \
+          disorder_actions.5.head disorder_templates.5.head \
+          disorder_actions.5.tail disorder_templates.5.tail \
+          disorder_options.5.in disorder.cgi.8.in
 
 CLEANFILES=$(SEDFILES) $(HTMLMAN) $(TMPLMAN)
 
index e1981f62df5b218181f1791dd1e8005fe3aaac36..bd22e56d9baa7de8c721abe92d065a8c57399276 100644 (file)
@@ -393,7 +393,7 @@ Per-user password file
 Communication socket for \fBdisorder\fR(1).
 .SH "SEE ALSO"
 \fBdisorderd\fR(8), \fBdisorder_config\fR(5), \fBsyslog\fR(3), \fBtime\fR(2),
-\fBpcrepattern\fR(3), \fBdisobedience\fR(1)
+\fBpcrepattern\fR(3), \fBdisobedience\fR(1), \fBdisorder.cgi\fR(8)
 .PP
 "\fBpydoc disorder\fR" for the Python API documentation.
 .\" Local Variables:
diff --git a/doc/disorder.cgi.8.in b/doc/disorder.cgi.8.in
new file mode 100644 (file)
index 0000000..833e114
--- /dev/null
@@ -0,0 +1,51 @@
+.\"
+.\" Copyright (C) 2008 Richard Kettlewell
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful, but
+.\" WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+.\" General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+.\" USA
+.\"
+.TH disorder.cgi 8
+.SH NAME
+disorder.cgi - DisOrder web interface
+.SH DESCRIPTION
+.B disorder.cgi
+is the web interface for DisOrder.  It runs as a CGI executable under
+(for example) Apache.
+.PP
+By default it will connect as the "guest" user.  This implies that
+\fBdisorder setup-guest\fR must have been run on the server for the
+CGI to work effectively, though it should be possible to manage
+without.
+.PP
+See \fBdisorder_actions\fR(5) for a description of what the CGI does.
+.PP
+See \fBdisorder_options\fR(5) for CGI-specific configuration and
+\dBdisorder_config\fR(5) for general configuration.
+.PP
+See \fBdisorder_templates\fR(5) for the template language used.
+.SH "WHERE IS IT?"
+The DisOrder makefiles don't know where to install the CGI, or indeed
+whether you wanted it installed, so they do not install it at all.
+You must copy it into the right location according to your web
+server's configuration.
+.SH "SEE ALSO"
+.BR disorder_config (5),
+.BR disorder_options (5),
+.BR disorder_templates (5),
+.BR disorder_actions (5)
+.\" Local Variables:
+.\" mode:nroff
+.\" fill-column:79
+.\" End:
diff --git a/doc/disorder_actions.5.head b/doc/disorder_actions.5.head
new file mode 100644 (file)
index 0000000..34367e7
--- /dev/null
@@ -0,0 +1,57 @@
+.\"
+.\" Copyright (C) 2008 Richard Kettlewell
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful, but
+.\" WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+.\" General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+.\" USA
+.\"
+.TH disorder_actions 5
+.SH NAME
+disorder_actions - DisOrder CGI actions
+.SH DESCRIPTION
+The primary CGI parameter to the DisOrder web interface is \fBaction\fR.
+This determines which of a set of actions from the list below it carries out.
+.PP
+For any action \fIACTION\fR not in the list, the CGI expands the template
+\fIACTION\fB.tmpl\fR.
+.PP
+If no action is set, then the default is \fBplaying\fR, unless the argument
+\fBc\fR is present, in which case it is \fBconfirm\fR.
+This is a hack to keep confirmation URLs short.
+.SS Redirection
+For actions in the list, if it is not specified what template they expand, they
+redirect according to the value of the \fBback\fR argument.
+There are three possibilities:
+.TP
+.BR 1 )
+\fBback\fR is a URL.
+The browser is redirected to that URL.
+.TP
+.BR 2 )
+\fBback\fR is an action name.
+The browser is redirected to a URL which uses that action.
+.TP
+.BR 3 )
+\fBback\fR is not set.
+The browser is redirected to the front page.
+.PP
+If an action needs more rights than the logged-in user has then they are
+redirected to \fBlogin\fR with \fBback\fR set to retry the action they wanted.
+.PP
+Certain errors cause a redirection to \fBerror\fR with \fB@error\fR set.
+.SH ACTIONS
+.\" Local Variables:
+.\" mode:nroff
+.\" fill-column:79
+.\" End:
diff --git a/doc/disorder_actions.5.tail b/doc/disorder_actions.5.tail
new file mode 100644 (file)
index 0000000..9c95521
--- /dev/null
@@ -0,0 +1,26 @@
+.\"
+.\" Copyright (C) 2008 Richard Kettlewell
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful, but
+.\" WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+.\" General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+.\" USA
+.\"
+.SH "SEE ALSO"
+.BR disorder_templates (5),
+.BR disorder_config (5),
+.BR disorder.cgi (8)
+.\" Local Variables:
+.\" mode:nroff
+.\" fill-column:79
+.\" End:
index 2c36aa8ad396e39d6838622ff79b1239237c0675..a774cc65a80a6a6f983e5ea39db22c9aa2a2242a 100644 (file)
@@ -145,6 +145,8 @@ This model will be changed in a future version.)
 Access control to the web interface is (currently) separate from DisOrder's own
 access control (HTTP authentication is required) but uses the same user
 namespace.
+.PP
+See \fBdisorder.cgi\fR(8) for more information.
 .SS "Searching And Tags"
 Search strings contain a list of search terms separated by spaces.
 A search term can either be a single word or a tag, prefixed with "tag:".
@@ -830,195 +832,6 @@ If this is set to a nonzero value then the driver will call \fB_exit\fR(2) if a
 write to the output file descriptor fails.
 This is a workaround for buggy players such as \fBogg123\fR that ignore
 write errors.
-.SH "WEB TEMPLATES"
-When \fBdisorder.cgi\fR wants to generate a page for action ACTION, it looks
-for ACTION.tmpl first in pkgconfdir and then in pkgdatadir.  Customization can
-be achieved by copy the desired templates to pkgconfdir and editing.  (Leave
-the ones in pkgdatadir alone, they will be overwritten on upgrade.)
-.PP
-The supplied templates are:
-.TP
-.B about.tmpl
-Display information about DisOrder.
-.TP
-.B choose.tmpl
-Navigates through the track database to choose a track to play.
-.TP
-.B login.tmpl
-The login page.
-.TP
-.B new.tmpl
-Lists newly added tracks.
-.TP
-.B playing.tmpl
-The "front page", which usually shows the currently playing tracks and
-the queue.
-Gets an HTTP \fBRefresh\fR header.
-.IP
-If the \fBmgmt\fR CGI argument is set to \fBtrue\fR then we include extra
-buttons for moving tracks up and down in the queue.
-There is some logic in \fBdisorder.cgi\fR to ensure that \fBmgmt=true\fR
-is preserved across refreshes and redirects back into itself, but
-URLs embedded in web pages must include it explicitly.
-.TP
-.B prefs.tmpl
-Views preferences.
-If the \fBfile\fR, \fBname\fR and \fBvalue\fR arguments are
-all set then that preference is modified; if \fBfile\fR and \fBname\fR are set
-but not \fBvalue\fR then the preference is deleted.
-.TP
-.B recent.tmpl
-Lists recently played tracks.
-.PP
-See \fBdisorder_templates\fR(5) for the syntax of template files.
-.SH "WEB OPTIONS"
-This is a file called \fIoptions\fR, searched for in the same manner
-as templates.
-It includes numerous options for the control of the web interface.
-The general syntax is the same as the main configuration
-file, except that it should be encoded using UTF-8 (though this might
-change to the current locale's character encoding; stick to ASCII to
-be safe).
-.PP
-The shipped \fIoptions\fR file includes four standard options files.
-In order, they are:
-.TP
-.I options.labels
-The default labels file.
-You wouldn't normally edit this directly - instead supply your own commands
-in \fIoptions.user\fR.
-Have a look at the shipped version of the file for documentation of
-labels used by the standard templates.
-.TP
-.I options.user
-A user options file.
-Here you should put any overrides for the default labels and any
-extra labels required by your modified templates.
-.PP
-Valid directives are:
-.TP
-.B columns \fINAME\fR \fIHEADING\fR...
-Defines the columns used in \fB@playing@\fR and \fB@recent@\fB.
-\fINAME\fR must be either \fBplaying\fR, \fBrecent\fR or \fBsearch\fR.
-\fIHEADING\fR...  is a list of heading names.
-If a column is defined more than once then the last definitions is used.
-.IP
-The heading names \fBbutton\fR, \fBlength\fR, \fBwhen\fR and \fBwho\fR
-are built in.
-.TP
-.B include \fIPATH\fR
-Includes another file.
-If \fIPATH\fR starts with a \fB/\fR then it is taken as is, otherwise
-it is searched for in the template path.
-.TP
-.B label \fINAME\fR \fIVALUE\fR
-Define a label.
-If a label is defined more than once then the last definition is used.
-.SS Labels
-Some labels are defined inside \fBdisorder.cgi\fR and others by the
-default templates.
-You can define your own labels and use them inside a template.
-.PP
-When an undefined label is expanded, if it has a dot in its name then
-the part after the final dot is used as its value.
-Otherwise the whole name is used as the value.
-.PP
-Labels are no longer documented here, see the shipped \fIoptions.labels\fR file
-instead.
-.SH "ACTIONS"
-What the web interface actually does is terminated by the \fBaction\fR CGI
-argument.
-The values listed below are supported.
-.PP
-Except as specified, all actions redirect back to the \fBplaying.html\fR
-template unless the \fBback\fR argument is present, in which case the URL it
-gives is used instead.
-.PP
-Redirection to \fBplaying.html\fR preserves \fBmgmt=true\fR if it is present.
-.TP 8
-.B "move"
-Move track \fBid\fR by offset \fBdelta\fR.
-.TP
-.B "play"
-Play track \fBfile\fR, or if that is missing then play all the tracks in
-\fBdirectory\fR.
-.TP
-.B "playing"
-Don't change any state, but instead compute a suitable refresh time and include
-that in an HTTP header.
-Expands the \fBplaying.html\fR template rather than redirecting.
-.IP
-This is the default if \fBaction\fR is missing.
-.TP
-.B "random\-disable"
-Disables random play.
-.TP
-.B "random\-enable"
-Enables random play.
-.TP
-.B "disable"
-Disables play completely.
-.TP
-.B "enable"
-Enables play.
-.TP
-.B "pause"
-Pauses the current track.
-.TP
-.B "remove"
-Remove track \fBid\fR.
-.TP
-.B "resume"
-Resumes play after a pause.
-.TP
-.B "scratch"
-Scratch the playing track.
-If \fBid\fR is present it must match the playing track.
-.TP
-.B "volume"
-Change the volume by \fBdelta\fR, or if that is missing then set it to the
-values of \fBleft\fR and \fBright\fR.
-Expands to the \fBvolume.html\fR template rather than redirecting.
-.TP
-.B "prefs"
-Adjust preferences from the \fBprefs.html\fR template (which it then expands
-rather than redirecting).
-.IP
-If
-.B parts
-is set then the cooked interface is assumed.
-The value of
-.B parts
-is used to determine which trackname preferences are set.
-By default the
-.B display
-context is adjusted but this can be overridden with the
-.B context
-argument.
-Also the
-.B random
-argument is checked; if it is set then random play is enabled for that track,
-otherwise it is disabled.
-.IP
-Otherwise if the
-.B name
-and
-.B value
-arguments are set then they are used to set a single preference.
-.IP
-Otherwise if just the
-.B name
-argument is set then that preference is deleted.
-.IP
-It is recommended that links to the \fBprefs\fR action use \fB@resolve@\fR to
-enure that the real track name is always used.
-Otherwise if the preferences page is used to adjust a trackname_ preference,
-the alias may change, leading to the URL going stale.
-.TP
-.B "error"
-This action is generated automatically when an error occurs connecting to the
-server.
-The \fBerror\fR label is set to an indication of what the error is.
 .SH "REGEXP SUBSTITUTION RULES"
 Regexps are PCRE regexps, as defined in \fBpcrepattern\fR(3).
 The only option used is \fBPCRE_UTF8\fR.
@@ -1054,7 +867,8 @@ name and \fBext\fR which is the filename extension, including the initial dot
 (or the empty string if there is not extension).
 .SH "SEE ALSO"
 \fBdisorder\fR(1), \fBsox\fR(1), \fBdisorderd\fR(8), \fBdisorder\-dump\fR(8),
-\fBpcrepattern\fR(3), \fBdisorder_templates\fR(5)
+\fBpcrepattern\fR(3), \fBdisorder_templates\fR(5), \fBdisorder_actions\fR(5),
+\fBdisorder.cgi\fR(8)
 .\" Local Variables:
 .\" mode:nroff
 .\" fill-column:79
diff --git a/doc/disorder_options.5.in b/doc/disorder_options.5.in
new file mode 100644 (file)
index 0000000..62dd9c2
--- /dev/null
@@ -0,0 +1,81 @@
+.\"
+.\" Copyright (C) 2008 Richard Kettlewell
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful, but
+.\" WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+.\" General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+.\" USA
+.\"
+.TH disorder_options 5
+.SH NAME
+pkgconfdir/options - DisOrder CGI actions
+.SH DESCRIPTION
+The DisOrder CGI reads much extra configuration information from
+\fIpkgconfdir/options\fR.
+The general syntax is the same as the main configuration file (see
+\fBdisorder_config\fR(5)).
+.SH DIRECTIVES
+Valid directives are:
+.TP
+.B columns \fINAME\fR \fIHEADING\fR...
+Defines the columns used in \fB@playing@\fR and \fB@recent@\fB.
+\fINAME\fR must be either \fBplaying\fR, \fBrecent\fR or \fBsearch\fR.
+\fIHEADING\fR...  is a list of heading names.
+If a column is defined more than once then the last definitions is used.
+.IP
+The heading names \fBbutton\fR, \fBlength\fR, \fBwhen\fR and \fBwho\fR
+are built in.
+.TP
+.B include \fIPATH\fR
+Includes another file.
+If \fIPATH\fR starts with a \fB/\fR then it is taken as is, otherwise
+it is searched for in \fIpkgconfdir\fR and \fIpkgdatadir\fR.
+.TP
+.B label \fINAME\fR \fIVALUE\fR
+Define a label.
+If a label is defined more than once then the last definition is used.
+.SH LABELS
+Some labels are defined inside \fBdisorder.cgi\fR and others by the
+default templates.
+You can define your own labels and use them inside a template.
+.PP
+When an undefined label is expanded, if it has a dot in its name then
+the part after the final dot is used as its value.
+Otherwise the whole name is used as the value.
+.PP
+Labels are not individually documented here, see the shipped
+\fIoptions.labels\fR file instead.
+.SH "OPTION FILES"
+The shipped \fIoptions\fR file includes four standard options files.
+In order, they are:
+.TP
+.I options.labels
+The default labels file.
+You wouldn't normally edit this directly - instead supply your own commands
+in \fIoptions.user\fR.
+Have a look at the shipped version of the file for documentation of
+labels used by the standard templates.
+.TP
+.I options.user
+A user options file.
+Here you should put any overrides for the default labels and any
+extra labels required by your modified templates.
+.SH "SEE ALSO"
+.BR disorder_config (5),
+.BR disorder_templates (5),
+.BR disorder_actions (5),
+.BR disorder.cgi (8)
+.\" Local Variables:
+.\" mode:nroff
+.\" fill-column:79
+.\" End:
index a73ec89a012f996dc92ac16a17b3b007c5b38278..0c88a6d8c47964b49cf6aa0292cb365e1b5eda2a 100644 (file)
@@ -29,7 +29,10 @@ For example, to represent the copyright sign, use \fB&copy;\fR or \fB&#xA9;\fR.
 If you know the decimal or hex unicode value for a character then you can use
 \fB&#NNN;\fR or \fB&#xHHHH;\fR respectively.
 .SH "SEE ALSO"
-.BR disorder_config (5)
+.BR disorder_actions (5),
+.BR disorder_options (5),
+.BR disorder_config (5) (5),
+.BR disorder.cgi (8)
 .\" Local Variables:
 .\" mode:nroff
 .\" fill-column:79
index ed488e98764827bdec8b13313a4d353cc1476c5e..b304e5af236b3303d712fe5be3f83cf6870e4f44 100644 (file)
@@ -165,7 +165,8 @@ This prevents multiple instances of DisOrder running simultaneously.
 Current locale.
 See \fBlocale\fR(7).
 .SH "SEE ALSO"
-\fBdisorder\fR(1), \fBdisorder_config\fR(5), \fBdisorder\-dump\fR(8)
+\fBdisorder\fR(1), \fBdisorder_config\fR(5), \fBdisorder\-dump\fR(8),
+\fBdisorder.cgi\fR(8)
 .\" Local Variables:
 .\" mode:nroff
 .\" End:
index 6675dec518f1018d2e2f3c87db5de5229a826940..24822bbf66d783e5fe1d30b3749a853a67d1dd8d 100644 (file)
@@ -96,7 +96,7 @@ char *mx_find(const char *name) {
   return path;
 }
 
-/* @include{TEMPLATE}@
+/*! @include{TEMPLATE}@
  *
  * Includes TEMPLATE.
  *
@@ -151,7 +151,7 @@ static int exp_include(int attribute((unused)) nargs,
   return 0;
 }
 
-/* @include{COMMAND}@
+/*! @include{COMMAND}@
  *
  * Executes COMMAND via the shell (using "sh -c") and copies its
  * standard output to the template output.  The shell command output
@@ -200,7 +200,7 @@ static int exp_shell(int attribute((unused)) nargs,
   return 0;
 }
 
-/* @if{CONDITION}{IF-TRUE}{IF-FALSE}@
+/*! @if{CONDITION}{IF-TRUE}{IF-FALSE}@
  *
  * If CONDITION is "true" then evaluates to IF-TRUE.  Otherwise
  * evaluates to IF-FALSE.  The IF-FALSE part is optional.
@@ -222,7 +222,7 @@ static int exp_if(int nargs,
     return 0;
 }
 
-/* @and{BRANCH}{BRANCH}...@
+/*! @and{BRANCH}{BRANCH}...@
  *
  * Expands to "true" if all the branches are "true" otherwise to "false".  If
  * there are no brances then the result is "true".  Only as many branches as
@@ -248,7 +248,7 @@ static int exp_and(int nargs,
   return mx_bool_result(output, result);
 }
 
-/* @or{BRANCH}{BRANCH}...@
+/*! @or{BRANCH}{BRANCH}...@
  *
  * Expands to "true" if any of the branches are "true" otherwise to "false".
  * If there are no brances then the result is "false".  Only as many branches
@@ -274,7 +274,7 @@ static int exp_or(int nargs,
   return mx_bool_result(output, result);
 }
 
-/* @not{CONDITION}@
+/*! @not{CONDITION}@
  *
  * Expands to "true" unless CONDITION is "true" in which case "false".
  */
@@ -285,7 +285,7 @@ static int exp_not(int attribute((unused)) nargs,
   return mx_bool_result(output, !mx_str2bool(args[0]));
 }
 
-/* @#{...}@
+/*! @#{...}@
  *
  * Expands to nothing.  The argument(s) are not fully evaluated, and no side
  * effects occur.
@@ -297,7 +297,7 @@ static int exp_comment(int attribute((unused)) nargs,
   return 0;
 }
 
-/* @urlquote{STRING}@
+/*! @urlquote{STRING}@
  *
  * URL-quotes a string, i.e. replaces any characters not safe to use unquoted
  * in a URL with %-encoded form.
@@ -312,7 +312,7 @@ static int exp_urlquote(int attribute((unused)) nargs,
     return 0;
 }
 
-/* @eq{S1}{S2}...@
+/*! @eq{S1}{S2}...@
  *
  * Expands to "true" if all the arguments are identical, otherwise to "false"
  * (i.e. if any pair of arguments differs).
@@ -336,7 +336,7 @@ static int exp_eq(int nargs,
   return mx_bool_result(output, result);
 }
 
-/* @ne{S1}{S2}...@
+/*! @ne{S1}{S2}...@
  *
  * Expands to "true" if all of the arguments differ from one another, otherwise
  * to "false" (i.e. if any value appears more than once).
@@ -360,7 +360,7 @@ static int exp_ne(int nargs,
   return mx_bool_result(output, result);
 }
 
-/* @discard{...}@
+/*! @discard{...}@
  *
  * Expands to nothing.  Unlike the comment expansion @#{...}, side effects of
  * arguments are not suppressed.  So this can be used to surround a collection
@@ -373,7 +373,7 @@ static int exp_discard(int attribute((unused)) nargs,
   return 0;
 }
 
-/* @define{NAME}{ARG1 ARG2...}{DEFINITION}@
+/*! @define{NAME}{ARG1 ARG2...}{DEFINITION}@
  *
  * Define a macro.  The macro will be called NAME and will act like an
  * expansion.  When it is expanded, the expansion is replaced by DEFINITION,
@@ -396,7 +396,7 @@ static int exp_define(int attribute((unused)) nargs,
   return 0;
 }
 
-/* @basename{PATH}
+/*! @basename{PATH}
  *
  * Expands to the UNQUOTED basename of PATH.
  */
@@ -407,7 +407,7 @@ static int exp_basename(int attribute((unused)) nargs,
   return sink_writes(output, d_basename(args[0])) < 0 ? -1 : 0;
 }
 
-/* @dirname{PATH}
+/*! @dirname{PATH}
  *
  * Expands to the UNQUOTED directory name of PATH.
  */
@@ -418,7 +418,7 @@ static int exp_dirname(int attribute((unused)) nargs,
   return sink_writes(output, d_dirname(args[0])) < 0 ? -1 : 0;
 }
 
-/* @q{STRING}
+/*! @q{STRING}
  *
  * Expands to STRING.
  */
index 84f1f42e33f890ea43f18a8ee799be1146e60d5a..51586ea4385d6872e154466a5ca93ff91da977e1 100755 (executable)
@@ -6,7 +6,7 @@ my $name;
 my $docs;
 while(defined($_ = <>)) {
   chomp;
-  if(!defined $name and m,^/\* (\@([a-z\-]+).*),) {
+  if(!defined $name and m,^/\*! (\@?([a-z\-]+).*),) {
     $name = $2;
     my $heading = $1;
     $docs = [$heading];
index 76892115747482b109a399ad54d3adda4ce7cb01..961fdec3e1b536ef21c761100f04e097eb6a0b09 100644 (file)
@@ -47,7 +47,20 @@ static void redirect(const char *url) {
     fatal(errno, "error writing to stdout");
 }
 
-/* 'playing' and 'manage' just add a Refresh: header */
+/*! playing
+ *
+ * Expands \fIplaying.tmpl\fR as if there was no special 'playing' action, but
+ * adds a Refresh: field to the HTTP header.  The maximum refresh interval is
+ * defined by \fBrefresh\fR (see \fBdisorder_config\fR(5)) but may be less if
+ * the end of the track is near.
+ */
+/*! manage
+ *
+ * Expands \fIplaying.tmpl\fR (NB not \fImanage.tmpl\fR) as if there was no
+ * special 'playing' action, and adds a Refresh: field to the HTTP header.  The
+ * maximum refresh interval is defined by \Bfrefresh\fR (see
+ * \fBdisorder_config\fR(5)) but may be less if the end of the track is near.
+ */
 static void act_playing(void) {
   long refresh = config->refresh;
   long length;
@@ -92,42 +105,71 @@ static void act_playing(void) {
   dcgi_expand("playing", 1);
 }
 
+/*! disable
+ *
+ * Disables play.
+ */
 static void act_disable(void) {
   if(dcgi_client)
     disorder_disable(dcgi_client);
   redirect(0);
 }
 
+/*! enable
+ *
+ * Enables play.
+ */
 static void act_enable(void) {
   if(dcgi_client)
     disorder_enable(dcgi_client);
   redirect(0);
 }
 
+/*! random-disable
+ *
+ * Disables random play.
+ */
 static void act_random_disable(void) {
   if(dcgi_client)
     disorder_random_disable(dcgi_client);
   redirect(0);
 }
 
+/*! random-enable
+ *
+ * Enables random play.
+ */
 static void act_random_enable(void) {
   if(dcgi_client)
     disorder_random_enable(dcgi_client);
   redirect(0);
 }
 
+/*! pause
+ *
+ * Pauses the current track (if there is one and it's not paused already).
+ */
 static void act_pause(void) {
   if(dcgi_client)
     disorder_pause(dcgi_client);
   redirect(0);
 }
 
+/*! resume
+ *
+ * Resumes the current track (if there is one and it's paused).
+ */
 static void act_resume(void) {
   if(dcgi_client)
     disorder_resume(dcgi_client);
   redirect(0);
 }
 
+/*! remove
+ *
+ * Removes the track given by the \fBid\fR argument.  If this is the currently
+ * playing track then it is scratched.
+ */
 static void act_remove(void) {
   const char *id;
   struct queue_entry *q;
@@ -159,6 +201,12 @@ static void act_remove(void) {
   redirect(0);
 }
 
+/*! move
+ *
+ * Moves the track given by the \fBid\fR argument the distance given by the
+ * \fBdelta\fR argument.  If this is positive the track is moved earlier in the
+ * queue and if negative, later.
+ */
 static void act_move(void) {
   const char *id, *delta;
   struct queue_entry *q;
@@ -183,6 +231,11 @@ static void act_move(void) {
   redirect(0);
 }
 
+/*! play
+ *
+ * Play the track given by the \fBtrack\fR argument, or if that is not set all
+ * the tracks in the directory given by the \fBdir\fR argument.
+ */
 static void act_play(void) {
   const char *track, *dir;
   char **tracks;
@@ -217,6 +270,14 @@ static int clamp(int n, int min, int max) {
   return n;
 }
 
+/*! volume
+ *
+ * If the \fBdelta\fR argument is set: adjust both channels by that amount (up
+ * if positive, down if negative).
+ *
+ * Otherwise if \fBleft\fR and \fBright\fR are set, set the channels
+ * independently to those values.
+ */
 static void act_volume(void) {
   const char *l, *r, *d;
   int nd;
@@ -271,6 +332,15 @@ static int login_as(const char *username, const char *password) {
   return 0;                             /* OK */
 }
 
+/*! login
+ *
+ * If \fBusername\fR and \fBpassword\fR are set (and the username isn't
+ * "guest") then attempt to log in using those credentials.  On success,
+ * redirects to the \fBback\fR argument if that is set, or just expands
+ * \fIlogin.tmpl\fI otherwise, with \fB@status\fR set to \fBloginok\fR.
+ *
+ * If they aren't set then just expands \fIlogin.tmpl\fI.
+ */
 static void act_login(void) {
   const char *username, *password;
 
@@ -297,6 +367,11 @@ static void act_login(void) {
   }
 }
 
+/*! logout
+ *
+ * Logs out the current user and expands \fIlogin.tmpl\fR with \fBstatus\fR or
+ * \fB@error\fR set according to the result.
+ */
 static void act_logout(void) {
   if(dcgi_client) {
     /* Ask the server to revoke the cookie */
@@ -317,6 +392,12 @@ static void act_logout(void) {
   dcgi_expand("login", 1);
 }
 
+/*! register
+ *
+ * Register a new user using \fBusername\fR, \fBpassword1\fR, \fBpassword2\fR
+ * and \fBemail\fR and expands \fIlogin.tmpl\fR with \fBstatus\fR or
+ * \fB@error\fR set according to the result.
+ */
 static void act_register(void) {
   const char *username, *password, *password2, *email;
   char *confirm, *content_type;
@@ -378,6 +459,12 @@ static void act_register(void) {
   dcgi_expand("login", 1);
 }
 
+/*! confirm
+ *
+ * Confirm a user registration using the nonce supplied in \fBc\fR and expands
+ * \fIlogin.tmpl\fR with \fBstatus\fR or \fB@error\fR set according to the
+ * result.
+ */
 static void act_confirm(void) {
   const char *confirmation;
 
@@ -408,6 +495,12 @@ static void act_confirm(void) {
   dcgi_expand("login", 1);
 }
 
+/*! edituser
+ *
+ * Edit user details using \fBusername\fR, \fBchangepassword1\fR,
+ * \fBchangepassword2\fR and \fBemail\fR and expands \fIlogin.tmpl\fR with
+ * \fBstatus\fR or \fB@error\fR set according to the result.
+ */
 static void act_edituser(void) {
   const char *email = cgi_get("email"), *password = cgi_get("changepassword1");
   const char *password2 = cgi_get("changepassword2");
@@ -463,6 +556,12 @@ static void act_edituser(void) {
   dcgi_expand("login", 1);
 }
 
+/*! reminder
+ *
+ * Issue an email password reminder to \fBusername\fR and expands
+ * \fIlogin.tmpl\fR with \fBstatus\fR or \fB@error\fR set according to the
+ * result.
+ */
 static void act_reminder(void) {
   const char *const username = cgi_get("username");
 
@@ -539,6 +638,30 @@ static int process_prefs(int numfile) {
   return 0;
 }
 
+/*! prefs
+ *
+ * Set preferences on a number of tracks.
+ *
+ * The tracks to modify are specified in arguments \fB0_track\fR, \fB1_track\fR
+ * etc.  The number sequence must be contiguous and start from 0.
+ *
+ * For each track \fIINDEX\fB_track\fR:
+ * - \fIINDEX\fB_\fIPART\fR is used to set the trackname preference for
+ * that part.  (See \fBparts\fR below.)
+ * - \fIINDEX\fB_\fIrandom\fR if present enables random play for this track
+ * or disables it if absent.
+ * - \fIINDEX\fB_\fItags\fR sets the list of tags for this track.
+ * - \fIINDEX\fB_\fIweight\fR sets the weight for this track.
+ *
+ * \fBparts\fR can be set to the track name parts to modify.  The default is
+ * "artist album title".
+ *
+ * \fBcontext\fR can be set to the context to modify.  The default is
+ * "display".
+ *
+ * If the server detects a preference being set to its default, it removes the
+ * preference, thus keeping the database tidy.
+ */
 static void act_set(void) {
   int numfile;
 
index a0745736cd5781fb2f2aabe461794b3da927a00c..2dc809852d648c4533d4cf0172b779b1117c20c3 100644 (file)
@@ -38,7 +38,7 @@ static const char *make_index(int i) {
   return s;
 }
 
-/* @server-version
+/*! @server-version
  *
  * Expands to the server's version string, or a (safe to use) error
  * value if the server is unavailable or broken.
@@ -57,7 +57,7 @@ static int exp_server_version(int attribute((unused)) nargs,
   return sink_writes(output, cgi_sgmlquote(v)) < 0 ? -1 : 0;
 }
 
-/* @version
+/*! @version
  *
  * Expands to the local version string.
  */
@@ -69,7 +69,7 @@ static int exp_version(int attribute((unused)) nargs,
                      cgi_sgmlquote(disorder_short_version_string)) < 0 ? -1 : 0;
 }
 
-/* @url
+/*! @url
  *
  * Expands to the base URL of the web interface.
  */
@@ -81,7 +81,7 @@ static int exp_url(int attribute((unused)) nargs,
                      cgi_sgmlquote(config->url)) < 0 ? -1 : 0;
 }
 
-/* @arg{NAME}
+/*! @arg{NAME}
  *
  * Expands to the UNQUOTED form of CGI argument NAME, or the empty string if
  * there is no such argument.  Use @argq for a quick way to quote the argument.
@@ -98,7 +98,7 @@ static int exp_arg(int attribute((unused)) nargs,
     return 0;
 }
 
-/* @argq{NAME}
+/*! @argq{NAME}
  *
  * Expands to the (quoted) form of CGI argument NAME, or the empty string if
  * there is no such argument.  Use @arg for the unquoted argument.
@@ -115,7 +115,7 @@ static int exp_argq(int attribute((unused)) nargs,
     return 0;
 }
 
-/* @user
+/*! @user
  *
  * Expands to the logged-in username (which might be "guest"), or to
  * the empty string if not connected.
@@ -131,7 +131,7 @@ static int exp_user(int attribute((unused)) nargs,
   return 0;
 }
 
-/* @part{TRACK|ID}{PART}{CONTEXT}
+/*! @part{TRACK|ID}{PART}{CONTEXT}
  *
  * Expands to a track name part.
  *
@@ -168,7 +168,7 @@ static int exp_part(int nargs,
   return 0;
 }
 
-/* @quote{STRING}
+/*! @quote{STRING}
  *
  * SGML-quotes STRING.  Note that most expansion results are already suitable
  * quoted, so this expansion is usually not required.
@@ -180,7 +180,7 @@ static int exp_quote(int attribute((unused)) nargs,
   return sink_writes(output, cgi_sgmlquote(args[0])) < 0 ? -1 : 0;
 }
 
-/* @who{ID}
+/*! @who{ID}
  *
  * Expands to the name of the submitter of track ID, which must be a playing
  * track, in the queue, or in the recent list.
@@ -196,7 +196,7 @@ static int exp_who(int attribute((unused)) nargs,
   return 0;
 }
 
-/* @when{ID}
+/*! @when{ID}
  *
  * Expands to the time a track started or is expected to start.  The track must
  * be a playing track, in the queue, or in the recent list.
@@ -233,7 +233,7 @@ static int exp_when(int attribute((unused)) nargs,
   return sink_writes(output, "&nbsp;") < 0 ? -1 : 0;
 }
 
-/* @length{ID|TRACK}
+/*! @length{ID|TRACK}
  *
  * Expands to the length of a track, identified by its queue ID or its name.
  * If it is the playing track (identified by ID) then the amount played so far
@@ -265,7 +265,7 @@ static int exp_length(int attribute((unused)) nargs,
   return sink_writes(output, "&nbsp;") < 0 ? -1 : 0;
 }
 
-/* @removable{ID}
+/*! @removable{ID}
  *
  * Expands to "true" if track ID is removable (or scratchable, if it is the
  * playing track) and "false" otherwise.
@@ -285,7 +285,7 @@ static int exp_removable(int attribute((unused)) nargs,
                             (dcgi_rights, disorder_user(dcgi_client), q));
 }
 
-/* @movable{ID}{DIR}
+/*! @movable{ID}{DIR}
  *
  * Expands to "true" if track ID is movable and "false" otherwise.
  *
@@ -318,7 +318,7 @@ static int exp_movable(int  nargs,
                                       q));
 }
 
-/* @playing{TEMPLATE}
+/*! @playing{TEMPLATE}
  *
  * Expands to TEMPLATE, with the following expansions:
  * - @id: the queue ID of the playing track
@@ -346,7 +346,7 @@ static int exp_playing(int nargs,
                    output, u);
 }
 
-/* @queue{TEMPLATE}
+/*! @queue{TEMPLATE}
  *
  * For each track in the queue, expands TEMPLATE with the following expansions:
  * - @id: the queue ID of the track
@@ -378,7 +378,7 @@ static int exp_queue(int attribute((unused)) nargs,
   return 0;
 }
 
-/* @recent{TEMPLATE}
+/*! @recent{TEMPLATE}
  *
  * For each track in the recently played list, expands TEMPLATE with the
  * following expansions:
@@ -411,7 +411,7 @@ static int exp_recent(int attribute((unused)) nargs,
   return 0;
 }
 
-/* @new{TEMPLATE}
+/*! @new{TEMPLATE}
  *
  * For each track in the newly added list, expands TEMPLATE wit the following
  * expansions:
@@ -445,7 +445,7 @@ static int exp_new(int attribute((unused)) nargs,
   return 0;
 }
 
-/* @volume{CHANNEL}
+/*! @volume{CHANNEL}
  *
  * Expands to the volume in a given channel.  CHANNEL must be "left" or
  * "right".
@@ -460,7 +460,7 @@ static int exp_volume(int attribute((unused)) nargs,
                          ? dcgi_volume_left : dcgi_volume_right) < 0 ? -1 : 0;
 }
 
-/* @isplaying
+/*! @isplaying
  *
  * Expands to "true" if there is a playing track, otherwise "false".
  */
@@ -472,7 +472,7 @@ static int exp_isplaying(int attribute((unused)) nargs,
   return mx_bool_result(output, !!dcgi_playing);
 }
 
-/* @isqueue
+/*! @isqueue
  *
  * Expands to "true" if there the queue is nonempty, otherwise "false".
  */
@@ -484,7 +484,7 @@ static int exp_isqueue(int attribute((unused)) nargs,
   return mx_bool_result(output, !!dcgi_queue);
 }
 
-/* @isrecent@
+/*! @isrecent@
  *
  * Expands to "true" if there the recently played list is nonempty, otherwise
  * "false".
@@ -497,7 +497,7 @@ static int exp_isrecent(int attribute((unused)) nargs,
   return mx_bool_result(output, !!dcgi_recent);
 }
 
-/* @isnew
+/*! @isnew
  *
  * Expands to "true" if there the newly added track list is nonempty, otherwise
  * "false".
@@ -510,7 +510,7 @@ static int exp_isnew(int attribute((unused)) nargs,
   return mx_bool_result(output, !!dcgi_nnew);
 }
 
-/* @pref{TRACK}{KEY}
+/*! @pref{TRACK}{KEY}
  *
  * Expands to a track preference.
  */
@@ -525,7 +525,7 @@ static int exp_pref(int attribute((unused)) nargs,
   return 0;
 }
 
-/* @prefs{TRACK}{TEMPLATE}
+/*! @prefs{TRACK}{TEMPLATE}
  *
  * For each track preference of track TRACK, expands TEMPLATE with the
  * following expansions:
@@ -564,7 +564,7 @@ static int exp_prefs(int attribute((unused)) nargs,
   return 0;
 }
 
-/* @transform{TRACK}{TYPE}{CONTEXT}
+/*! @transform{TRACK}{TYPE}{CONTEXT}
  *
  * Transforms a track name (if TYPE is "track") or directory name (if type is
  * "dir").  CONTEXT should be the context, if it is left out then "display" is
@@ -579,7 +579,7 @@ static int exp_transform(int nargs,
   return sink_writes(output, cgi_sgmlquote(t)) < 0 ? -1 : 0;
 }
 
-/* @enabled@
+/*! @enabled@
  *
  * Expands to "true" if playing is enabled, otherwise "false".
  */
@@ -594,7 +594,7 @@ static int exp_enabled(int attribute((unused)) nargs,
   return mx_bool_result(output, e);
 }
 
-/* @random-enabled
+/*! @random-enabled
  *
  * Expands to "true" if random play is enabled, otherwise "false".
  */
@@ -609,7 +609,7 @@ static int exp_random_enabled(int attribute((unused)) nargs,
   return mx_bool_result(output, e);
 }
 
-/* @trackstate{TRACK}
+/*! @trackstate{TRACK}
  *
  * Expands to "playing" if TRACK is currently playing, or "queue" if it is in
  * the queue, otherwise to nothing.
@@ -635,7 +635,7 @@ static int exp_trackstate(int attribute((unused)) nargs,
   return 0;
 }
 
-/* @thisurl
+/*! @thisurl
  *
  * Expands to an UNQUOTED URL which points back to the current page.  (NB it
  * might not be byte for byte identical - for instance, CGI arguments might be
@@ -648,7 +648,7 @@ static int exp_thisurl(int attribute((unused)) nargs,
   return sink_writes(output, cgi_thisurl(config->url)) < 0 ? -1 : 0;
 }
 
-/* @resolve{TRACK}
+/*! @resolve{TRACK}
  *
  * Expands to an UNQUOTED name for the TRACK that is not an alias, or to
  * nothing if it is not a valid track.
@@ -664,7 +664,7 @@ static int exp_resolve(int attribute((unused)) nargs,
   return 0;
 }
 
-/* @paused
+/*! @paused
  *
  * Expands to "true" if the playing track is paused, to "false" if it is
  * playing (or if there is no playing track at all).
@@ -678,7 +678,7 @@ static int exp_paused(int attribute((unused)) nargs,
                                  && dcgi_playing->state == playing_paused));
 }
 
-/* @state{ID}@
+/*! @state{ID}@
  *
  * Expands to the current state of track ID.
  */
@@ -693,7 +693,7 @@ static int exp_state(int attribute((unused)) nargs,
   return 0;
 }
 
-/* @right{RIGHT}{WITH-RIGHT}{WITHOUT-RIGHT}@
+/*! @right{RIGHT}{WITH-RIGHT}{WITHOUT-RIGHT}@
  *
  * Expands to WITH-RIGHT if the current user has right RIGHT, otherwise to
  * WITHOUT-RIGHT.  The WITHOUT-RIGHT argument may be left out.
@@ -730,7 +730,7 @@ static int exp_right(int nargs,
   return 0;
 }
 
-/* @userinfo{PROPERTY}
+/*! @userinfo{PROPERTY}
  *
  * Expands to the named property of the current user.
  */
@@ -747,7 +747,7 @@ static int exp_userinfo(int attribute((unused)) nargs,
   return 0;
 }
 
-/* @error
+/*! @error
  *
  * Expands to the latest error string.
  */
@@ -759,7 +759,7 @@ static int exp_error(int attribute((unused)) nargs,
               < 0 ? -1 : 0;
 }
 
-/* @status
+/*! @status
  *
  * Expands to the latest status string.
  */
@@ -771,7 +771,7 @@ static int exp_status(int attribute((unused)) nargs,
               < 0 ? -1 : 0;
 }
 
-/* @image{NAME}
+/*! @image{NAME}
  *
  * Expands to the URL of the image called NAME.
  *
@@ -878,7 +878,7 @@ static int exp__files_dirs(int nargs,
 
 }
 
-/* @tracks{DIR}{RE}{TEMPLATE}
+/*! @tracks{DIR}{RE}{TEMPLATE}
  *
  * For each track below DIR, expands TEMPLATE with the
  * following expansions:
@@ -899,7 +899,7 @@ static int exp_tracks(int nargs,
   return exp__files_dirs(nargs, args, output, u, "track", disorder_files);
 }
 
-/* @dirs{DIR}{RE}{TEMPLATE}
+/*! @dirs{DIR}{RE}{TEMPLATE}
  *
  * For each directory below DIR, expands TEMPLATE with the
  * following expansions:
@@ -926,7 +926,7 @@ static int exp__search_shim(disorder_client *c, const char *terms,
   return disorder_search(c, terms, vecp, nvecp);
 }
 
-/* @search{KEYWORDS}{TEMPLATE}
+/*! @search{KEYWORDS}{TEMPLATE}
  *
  * For each track matching KEYWORDS, expands TEMPLATE with the
  * following expansions:
@@ -945,7 +945,7 @@ static int exp_search(int nargs,
   return exp__files_dirs(nargs, args, output, u, "track", exp__search_shim);
 }
 
-/* @label{NAME}
+/*! @label{NAME}
  *
  * Expands to label NAME from options.labels.  Undefined lables expand to the
  * last dot-separated component, e.g. X.Y.Z to Z.
@@ -957,7 +957,7 @@ static int exp_label(int attribute((unused)) nargs,
   return sink_writes(output, option_label(args[0])) < 0 ? -1 : 0;
 }
 
-/* @breadcrumbs{DIR}{TEMPLATE}
+/*! @breadcrumbs{DIR}{TEMPLATE}
  *
  * Expands TEMPLATE for each directory in the path up to DIR, excluding the root
  * but including DIR itself, with the following expansions: