chiark / gitweb /
Bring CGI docs pretty much up to date
[disorder] / server / macros-disorder.c
index a08f0ed767a77ff34c0f2f99d43362da318e44a8..2dc809852d648c4533d4cf0172b779b1117c20c3 100644 (file)
@@ -1,3 +1,4 @@
+
 /*
  * This file is part of DisOrder.
  * Copyright (C) 2004-2008 Richard Kettlewell
 #include "disorder-cgi.h"
 
 /** @brief For error template */
-char *dcgi_error_string;
+const char *dcgi_error_string;
 
 /** @brief For login template */
-char *dcgi_status_string;
+const char *dcgi_status_string;
 
 /** @brief Return @p i as a string */
 static const char *make_index(int i) {
@@ -37,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.
@@ -56,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.
  */
@@ -68,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.
  */
@@ -80,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.
@@ -97,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.
@@ -114,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.
@@ -130,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.
  *
@@ -167,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.
@@ -179,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.
@@ -195,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.
@@ -232,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
@@ -264,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.
@@ -284,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.
  *
@@ -317,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
@@ -345,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
@@ -377,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:
@@ -410,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:
@@ -444,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".
@@ -459,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".
  */
@@ -471,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".
  */
@@ -483,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".
@@ -496,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".
@@ -509,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.
  */
@@ -524,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:
@@ -563,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
@@ -578,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".
  */
@@ -593,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".
  */
@@ -608,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.
@@ -634,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
@@ -647,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.
@@ -663,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).
@@ -677,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.
  */
@@ -692,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.
@@ -729,7 +730,7 @@ static int exp_right(int nargs,
   return 0;
 }
 
-/* @userinfo{PROPERTY}
+/*! @userinfo{PROPERTY}
  *
  * Expands to the named property of the current user.
  */
@@ -746,7 +747,7 @@ static int exp_userinfo(int attribute((unused)) nargs,
   return 0;
 }
 
-/* @error
+/*! @error
  *
  * Expands to the latest error string.
  */
@@ -758,7 +759,7 @@ static int exp_error(int attribute((unused)) nargs,
               < 0 ? -1 : 0;
 }
 
-/* @status
+/*! @status
  *
  * Expands to the latest status string.
  */
@@ -770,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.
  *
@@ -877,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:
@@ -898,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:
@@ -925,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:
@@ -944,6 +945,11 @@ static int exp_search(int nargs,
   return exp__files_dirs(nargs, args, output, u, "track", exp__search_shim);
 }
 
+/*! @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.
+ */
 static int exp_label(int attribute((unused)) nargs,
                      char **args,
                      struct sink *output,
@@ -951,6 +957,48 @@ static int exp_label(int attribute((unused)) nargs,
   return sink_writes(output, option_label(args[0])) < 0 ? -1 : 0;
 }
 
+/*! @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:
+ * - @dir: the directory
+ * - @last: "true" if this is the last directory, otherwise "false"
+ *
+ * DIR must be an absolute path.
+ */
+static int exp_breadcrumbs(int attribute((unused)) nargs,
+                           const struct mx_node **args,
+                           struct sink *output,
+                           void attribute((unused)) *u) {
+  int rc;
+  char *dir, *parent, *ptr;
+  
+  if((rc = mx_expandstr(args[0], &dir, u, "argument #0 (DIR)")))
+    return rc;
+  /* Reject relative paths */
+  if(dir[0] != '/') {
+    error(0, "breadcrumbs: '%s' is a relative path", dir);
+    return 0;
+  }
+  /* Skip the root */
+  ptr = dir + 1;
+  while(*ptr) {
+    /* Find the end of this directory */
+    while(*ptr && *ptr != '/')
+      ++ptr;
+    parent = xstrndup(dir, ptr - dir);
+    if((rc = mx_expand(mx_rewritel(args[1],
+                                   "dir", parent,
+                                   "last", *ptr ? "false" : "true",
+                                   (char *)0),
+                       output, u)))
+      return rc;
+    if(*ptr)
+      ++ptr;
+  }
+  return 0;
+}
+  
 /** @brief Register DisOrder-specific expansions */
 void dcgi_expansions(void) {
   mx_register("arg", 1, 1, exp_arg);
@@ -985,6 +1033,7 @@ void dcgi_expansions(void) {
   mx_register("volume", 1, 1, exp_volume);
   mx_register("when", 1, 1, exp_when);
   mx_register("who", 1, 1, exp_who);
+  mx_register_magic("breadcrumbs", 2, 2, exp_breadcrumbs);
   mx_register_magic("dirs", 2, 3, exp_dirs);
   mx_register_magic("new", 1, 1, exp_new);
   mx_register_magic("playing", 0, 1, exp_playing);