chiark / gitweb /
dirname/basename expansions; template fiddling
authorRichard Kettlewell <rjk@greenend.org.uk>
Sun, 11 May 2008 11:38:59 +0000 (12:38 +0100)
committerRichard Kettlewell <rjk@greenend.org.uk>
Sun, 11 May 2008 11:38:59 +0000 (12:38 +0100)
14 files changed:
lib/filepart.c
lib/filepart.h
lib/macros-builtin.c
lib/t-filepart.c
lib/t-macros.c
lib/test.c
lib/test.h
server/actions.c
server/cgimain.c
server/macros-disorder.c
templates/macros.tmpl
templates/playing.tmpl
templates/stdhead.tmpl
templates/stylesheet.tmpl

index c080b4d..7af7de0 100644 (file)
 #include "types.h"
 
 #include <string.h>
+#include <assert.h>
+#include <stdio.h>
 
 #include "filepart.h"
 #include "mem.h"
 
+/** @brief Parse a filename
+ * @param path Filename to parse
+ * @param Where to put directory name, or NULL
+ * @param Where to put basename, or NULL
+ */
+static void parse_filename(const char *path,
+                           char **dirnamep,
+                           char **basenamep) {
+  const char *s, *e = path + strlen(path);
+
+  /* Strip trailing slashes.  We never take these into account. */
+  while(e > path && e[-1] == '/')
+    --e;
+  if(e == path) {
+    /* The path is empty or contains only slashes */
+    if(*path) {
+      if(dirnamep)
+        *dirnamep = xstrdup("/");
+      if(basenamep)
+        *basenamep = xstrdup("/");
+    } else {
+      if(dirnamep)
+        *dirnamep = xstrdup("");
+      if(basenamep)
+        *basenamep = xstrdup("");
+    }
+  } else {
+    /* The path isn't empty and has more than just slashes.  e therefore now
+     * points at the end of the basename. */
+    s = e;
+    while(s > path && s[-1] != '/')
+      --s;
+    /* Now s points at the start of the basename */
+    if(basenamep)
+      *basenamep = xstrndup(s, e - s);
+    if(s > path) {
+      --s;
+      /* s must now be pointing at a '/' before the basename */
+      assert(*s == '/');
+      while(s > path && s[-1] == '/')
+        --s;
+      /* Now s must be pointing at the last '/' after the dirname */
+      assert(*s == '/');
+      if(s == path) {
+        /* If we reached the start we must be at the root */
+        if(dirnamep)
+          *dirnamep = xstrdup("/");
+      } else {
+        /* There's more than just the root here */
+        if(dirnamep)
+          *dirnamep = xstrndup(path, s - path);
+      }
+    } else {
+      /* There wasn't a slash */
+      if(dirnamep)
+        *dirnamep = xstrdup(".");
+    }
+  }
+}
+
 /** @brief Return the directory part of @p path
  * @param path Path to parse
  * @return Directory part of @p path
  *
  * Extracts the directory part of @p path.  This is a simple lexical
  * transformation and no canonicalization is performed.  The result will only
- * ever end "/" if it is the root directory.
+ * ever end "/" if it is the root directory.  The result will be "." if there
+ * is no directory part.
  */
 char *d_dirname(const char *path) {
-  const char *s;
+  char *d = 0;
 
-  if((s = strrchr(path, '/'))) {
-    while(s > path && s[-1] == '/')
-      --s;
-    if(s == path)
-      return xstrdup("/");
-    else
-      return xstrndup(path, s - path);
-  } else
-    return xstrdup(".");
+  parse_filename(path, &d, 0);
+  assert(d != 0);
+  return d;
+}
+
+/** @brief Return the basename part of @p path
+ * @param Path to parse
+ * @return Base part of @p path
+ *
+ * Extracts the base part of @p path.  This is a simple lexical transformation
+ * and no canonicalization is performed.  The result is always newly allocated
+ * even if compares equal to @p path.
+ */
+char *d_basename(const char *path) {
+  char *b = 0;
+
+  parse_filename(path, 0, &b);
+  assert(b != 0);
+  return b;
 }
 
 /** @brief Find the extension part of @p path
index fdc9074..9b6cf62 100644 (file)
@@ -24,6 +24,8 @@
 #ifndef FILEPART_H
 #define FILEPART_H
 
+char *d_basename(const char *path);
+
 char *d_dirname(const char *path);
 /* return the directory name part of @path@ */
 
index d8551fb..c96506f 100644 (file)
@@ -48,6 +48,7 @@
 #include "split.h"
 #include "printf.h"
 #include "vector.h"
+#include "filepart.h"
 
 static struct vector include_path;
 
@@ -395,13 +396,32 @@ static int exp_define(int attribute((unused)) nargs,
   return 0;
 }
 
+/* @basename{PATH}
+ *
+ * Expands to the UNQUOTED basename of PATH.
+ */
+static int exp_basename(int attribute((unused)) nargs,
+                        char **args,
+                        struct sink attribute((unused)) *output,
+                        void attribute((unused)) *u) {
+  return sink_writes(output, d_basename(args[0])) < 0 ? -1 : 0;
+}
+
+/* @dirname{PATH}
+ *
+ * Expands to the UNQUOTED directory name of PATH.
+ */
+static int exp_dirname(int attribute((unused)) nargs,
+                       char **args,
+                       struct sink attribute((unused)) *output,
+                       void attribute((unused)) *u) {
+  return sink_writes(output, d_dirname(args[0])) < 0 ? -1 : 0;
+}
+
 /** @brief Register built-in expansions */
 void mx_register_builtin(void) {
-  mx_register_magic("#", 0, INT_MAX, exp_comment);
-  mx_register_magic("and", 0, INT_MAX, exp_and);
-  mx_register_magic("define", 3, 3, exp_define);
-  mx_register_magic("if", 2, 3, exp_if);
-  mx_register_magic("or", 0, INT_MAX, exp_or);
+  mx_register("basename", 1, 1, exp_basename);
+  mx_register("dirname", 1, 1, exp_dirname);
   mx_register("discard", 0, INT_MAX, exp_discard);
   mx_register("eq", 0, INT_MAX, exp_eq);
   mx_register("include", 1, 1, exp_include);
@@ -409,6 +429,11 @@ void mx_register_builtin(void) {
   mx_register("not", 1, 1, exp_not);
   mx_register("shell", 1, 1, exp_shell);
   mx_register("urlquote", 1, 1, exp_urlquote);
+  mx_register_magic("#", 0, INT_MAX, exp_comment);
+  mx_register_magic("and", 0, INT_MAX, exp_and);
+  mx_register_magic("define", 3, 3, exp_define);
+  mx_register_magic("if", 2, 3, exp_if);
+  mx_register_magic("or", 0, INT_MAX, exp_or);
 }
 
 /** @brief Add a directory to the search path
index d2e741b..3eff101 100644 (file)
  */
 #include "test.h"
 
+#define check_filepart(PATH, DIR, BASE) do {            \
+  char *d = d_dirname(PATH), *b = d_basename(PATH);     \
+                                                        \
+  if(strcmp(d, DIR)) {                                  \
+    fprintf(stderr, "%s:%d: d_dirname failed:\n"        \
+            "    path: %s\n"                            \
+            "     got: %s\n"                            \
+            "expected: %s\n",                           \
+            __FILE__, __LINE__,                         \
+            PATH, d, DIR);                              \
+    count_error();                                      \
+  }                                                     \
+  if(strcmp(b, BASE)) {                                 \
+    fprintf(stderr, "%s:%d: d_basename failed:\n"       \
+            "    path: %s\n"                            \
+            "     got: %s\n"                            \
+            "expected: %s\n",                           \
+            __FILE__, __LINE__,                         \
+            PATH, d, DIR);                              \
+    count_error();                                      \
+  }                                                     \
+} while(0)
+
 static void test_filepart(void) {
-  check_string(d_dirname("/"), "/");
-  check_string(d_dirname("////"), "/");
-  check_string(d_dirname("/spong"), "/");
-  check_string(d_dirname("////spong"), "/");
-  check_string(d_dirname("/foo/bar"), "/foo");
-  check_string(d_dirname("////foo/////bar"), "////foo");
-  check_string(d_dirname("./bar"), ".");
-  check_string(d_dirname(".//bar"), ".");
-  check_string(d_dirname("."), ".");
-  check_string(d_dirname(".."), ".");
-  check_string(d_dirname("../blat"), "..");
-  check_string(d_dirname("..//blat"), "..");
-  check_string(d_dirname("wibble"), ".");
+  check_filepart("", "", "");
+  check_filepart("/", "/", "/");
+  check_filepart("////", "/", "/");
+  check_filepart("/spong", "/", "spong");
+  check_filepart("/spong/", "/", "spong");
+  check_filepart("/spong//", "/", "spong");
+  check_filepart("////spong", "/", "spong");
+  check_filepart("/foo/bar", "/foo", "bar");
+  check_filepart("/foo/bar/", "/foo", "bar");
+  check_filepart("////foo/////bar", "////foo", "bar");
+  check_filepart("./bar", ".", "bar");
+  check_filepart(".//bar", ".", "bar");
+  check_filepart(".", ".", ".");
+  check_filepart("..", ".", "..");
+  check_filepart("../blat", "..", "blat");
+  check_filepart("..//blat", "..", "blat");
+  check_filepart("wibble", ".", "wibble");
   check_string(extension("foo.c"), ".c");
   check_string(extension(".c"), ".c");
   check_string(extension("."), ".");
index 19bc14a..2bf747f 100644 (file)
@@ -213,6 +213,12 @@ static void test_macros(void) {
   fprintf(stderr, ">>> expect error message about 'if':\n");
   check_macro("badex3", "<@if{1}{2}{3}{4}{5}>",
               "<[['if' too many args]]>", 0);
+
+  check_macro("dirname1", "@dirname{foo/bar}", "foo", 0);
+  check_macro("dirname2", "@dirname{foo & something/bar}",
+              "foo & something", 0);
+  check_macro("basename1", "@basename{xyzzy/plugh}", "plugh", 0);
+  check_macro("basename2", "@basename{xyzzy/a<b}", "a<b", 0);
   
   /* Macro definitions ------------------------------------------------------ */
 
index 63d7260..f5dd036 100644 (file)
 /** @file lib/test.c @brief Library tests */
 
 #include "test.h"
+#include "version.h"
+#include <getopt.h>
 
 long long tests, errors;
 int fail_first;
+int verbose;
 
 void count_error(void) {
   ++errors;
@@ -34,7 +37,7 @@ const char *format(const char *s) {
   struct dynstr d;
   int c;
   char buf[10];
-  
+
   dynstr_init(&d);
   while((c = (unsigned char)*s++)) {
     if(c >= ' ' && c <= '~')
@@ -52,7 +55,7 @@ const char *format_utf32(const uint32_t *s) {
   struct dynstr d;
   uint32_t c;
   char buf[64];
-  
+
   dynstr_init(&d);
   while((c = *s++)) {
     sprintf(buf, " %04lX", (long)c);
@@ -90,6 +93,46 @@ const char *do_printf(const char *fmt, ...) {
   return s;
 }
 
+static const struct option options[] = {
+  { "verbose", no_argument, 0, 'v' },
+  { "fail-first", no_argument, 0, 'F' },
+  { "help", no_argument, 0, 'h' },
+  { "version", no_argument, 0, 'V' },
+};
+
+/* display usage message and terminate */
+static void help(void) {
+  xprintf("Usage:\n"
+         "  %s [OPTIONS]\n"
+         "Options:\n"
+         "  --help, -h               Display usage message\n"
+         "  --version, -V            Display version number\n"
+          "  --verbose, -v            Verbose output\n"
+          "  --fail-first, -F         Stop on first failure\n",
+          progname);
+  xfclose(stdout);
+  exit(0);
+}
+
+void test_init(int argc, char **argv) {
+  int n;
+
+  set_progname(argv);
+  mem_init();
+  while((n = getopt_long(argc, argv, "vFhV", options, 0)) >= 0) {
+    switch(n) {
+    case 'v': verbose = 1; break;
+    case 'F': fail_first = 1; break;
+    case 'h': help();
+    case 'V': version(progname);
+    default: exit(1);
+    }
+  }
+  if(getenv("FAIL_FIRST"))
+    fail_first = 1;
+}
+
+
 /*
 Local Variables:
 c-basic-offset:2
index 3c43da0..7a0ef5d 100644 (file)
@@ -72,6 +72,7 @@
 
 extern long long tests, errors;
 extern int fail_first;
+extern int verbose;
 
 /** @brief Checks that @p expr is nonzero */
 #define insist(expr) do {                              \
@@ -130,13 +131,13 @@ const char *format(const char *s);
 const char *format_utf32(const uint32_t *s);
 uint32_t *ucs4parse(const char *s);
 const char *do_printf(const char *fmt, ...);
+void test_init(int argc, char **argv);
 
 #define TEST(name)                                                      \
-   int main(void) {                                                     \
-    mem_init();                                                         \
-    fail_first = !!getenv("FAIL_FIRST");                                \
+  int main(int argc, char **argv) {                                     \
+    test_init(argc, argv);                                              \
     test_##name();                                                      \
-    if(errors)                                                          \
+    if(errors || verbose)                                               \
       fprintf(stderr, "test_"#name": %lld errors out of %lld tests\n",  \
               errors, tests);                                           \
     return !!errors;                                                    \
index 7b69932..1a6f7c9 100644 (file)
@@ -92,7 +92,7 @@ static void act_playing(void) {
             "\n",
             refresh, url, dcgi_cookie_header()) < 0)
     fatal(errno, "error writing to stdout");
-  dcgi_expand(action ? action : "playing");
+  dcgi_expand("playing");
 }
 
 static void act_disable(void) {
index 638a713..253f82e 100644 (file)
@@ -47,7 +47,8 @@ int main(int argc, char **argv) {
     configfile = xstrdup(conf);
   if(getenv("DISORDER_DEBUG"))
     debugging = 1;
-  if(config_read(0))
+  /* Read configuration */
+  if(config_read(0/*!server*/))
     exit(EXIT_FAILURE);
   /* Figure out our URL.  This can still be overridden from the config file if
    * necessary but it shouldn't be necessary in ordinary installations. */
@@ -68,7 +69,7 @@ int main(int argc, char **argv) {
   /* Create the initial connection, trying the cookie if we found a suitable
    * one. */
   dcgi_login();
-  /* The main program... */
+  /* Do whatever the user wanted */
   dcgi_action(NULL);
   /* In practice if a write fails that probably means the web server went away,
    * but we log it anyway. */
index bb920f4..e58324b 100644 (file)
@@ -105,6 +105,7 @@ static int exp_arg(int attribute((unused)) nargs,
                   struct sink *output,
                   void attribute((unused)) *u) {
   const char *s = cgi_get(args[0]);
+
   if(s)
     return sink_writes(output,
                        cgi_sgmlquote(s)) < 0 ? -1 : 0;
index 450783e..cb763b2 100644 (file)
@@ -18,9 +18,9 @@ along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 USA
 
-@define {action} {}
-        {@if {@arg:mgmt@}
-             {manage}
-             {@arg:action@}@}@
+@define {ifmanage} {yes} {no}
+        {@if {@eq {@arg{action}}{manage}}
+             {@yes}
+             {@no}}
 
 }@@@
index c016858..084f5c3 100644 (file)
@@ -1,4 +1,3 @@
-@include{macros.tmpl}@#
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
 <!--
 This file is part of DisOrder.
@@ -19,31 +18,41 @@ along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 USA
 -->
+@discard{
+  @define {ifmanage} {yes no}
+         {@if {@eq {@arg{action}}{manage}}
+              {@yes}
+              {@no}}
+  @define {back} {}
+          {@ifmanage{&amp;back=manage}{}}
+  @include{macros.tmpl}
+}@#
 <html>
  <head>
-@include{stdhead.tmpl}
+@include{stdhead.tmpl}@#
   <title>@if{@isplaying}
-             {@part{@playing}{title}@label{playing.title}}</title>
+            {@playing{@part{@id}{title}}}
+            {@label{playing.title}}</title>
  </head>
  <body>
 @include{topbar.tmpl}
    <h1>@label{playing.title}</h1>
 
 @# Extra control buttons for the management page
-   @if{@arg{mgmt}}{
+   @ifmanage{
    <div class=mgmt>
    <p class=mgmt>
     @if{@paused}{
 @# Paused
       <a class=button
-      href="@url?action=resume&#38;mgmt=true"
+      href="@url?action=resume@back"
        title="@label{playing.resumeverbose}">@label{playing.pause}</a>
       </a>
       <img width=16 height=16 class=imgbutton src="@image{enabled}">
     }{
 @# Not paused
       <a class=button
-      href="@url?action=pause&#38;mgmt=true"
+      href="@url?action=pause@back"
        title="@label{playing.pauseverbose}">@label{playing.pause}</a>
       </a>
       <img width=16 height=16 class=imgbutton src="@image{disabled}">
@@ -51,14 +60,14 @@ USA
     @if{@random-enabled}{
 @# Random play enabled
       <a class=button
-      href="@url?action=random-disable&#38;mgmt=true"
+      href="@url?action=random-disable@back"
        title="@label{playing.randomdisableverbose}">@label{playing.random}</a>
       </a>
       <img width=16 height=16 class=imgbutton src="@image{enabled}">
     }{
 @# Random play disabled
       <a class=button
-      href="@url?action=random-enable&#38;mgmt=true"
+      href="@url?action=random-enable@back"
        title="@label{playing.randomenableverbose}">@label{playing.random}</a>
       </a>
       <img width=16 height=16 class=imgbutton src="@image{disabled}">
@@ -66,19 +75,19 @@ USA
     @if{@enabled}{
 @# Play enabled
       <a class=button
-      href="@url?action=disable&#38;mgmt=true"
+      href="@url?action=disable@back"
        title="@label{playing.disableverbose}">@label{playing.playing}</a>
       </a>
       <img width=16 height=16 class=imgbutton src="@image{enabled}">
     }{
-@# Play disbaled
+@# Play disabled
       <a class=button
-      href="@url?action=enable&#38;mgmt=true"
+      href="@url?action=enable@back"
        title="@label{playing.enableverbose}">@label{playing.playing}</a>
       </a>
       <img width=16 height=16 class=imgbutton src="@image{disabled}">
     }
-@3 Volume form
+@# Volume form
     <form class=volume action="@url" method=POST
      enctype="multipart/form-data" accept-charset=utf-8>
     <span class=volume>
@@ -86,7 +95,7 @@ USA
 @# Volume up button
      @right{volume}{
        <a class=imgbutton
-        href="@url?action=volume&#38;delta=-@label{volume.resolution}&#38;back=manage">
+        href="@url?action=volume&#38;delta=-@label{volume.resolution}@back">
          <img class=button src="@image{down}"
               alt="@label{volume.reduce}"
               title="@label{volume.reduceverbose}">
@@ -97,7 +106,7 @@ USA
 @# Volume value widgets
      @label{volume.left} <input size=3 name=left type=text value="@volume:left@">
      @label{volume.right} <input size=3 name=right type=text value="@volume:right@">
-     <input name=back type=hidden value="@thisurl@?mgmt=true">
+     <input name=back type=hidden value="@thisurl@?back=manage">
 @# Volume set button
      @right{volume}{
        <button class=search name=submit type=submit>
@@ -107,7 +116,7 @@ USA
 @# Volume down button
      @right{volume}{
        <a class=imgbutton
-          href="@url?action=volume&#38;delta=@label{volume.resolution}&#38;back=manage">
+          href="@url?action=volume&#38;delta=@label{volume.resolution}@back">
           <img class=button
                src="@image{up}"
                alt="@label{volume.increase}"
@@ -120,7 +129,7 @@ USA
     </span>
     </p>
     </div>
-   }
+   }{}
 
 @# Only display the table if there is something to put in it
 @if{@or{@isplaying}{@isqueue}}{
@@ -133,85 +142,93 @@ USA
       <th class=title>@label{heading.title}</th>
       <th class=length>@label{heading.length}</th>
       <th class=button>&nbsp;</th>
-      @if{@arg{mgmt}}{
+      @ifmanage{
       <th class=imgbutton>&nbsp;</th>
       <th class=imgbutton>&nbsp;</th>
       <th class=imgbutton>&nbsp;</th>
       <th class=imgbutton>&nbsp;</th>
-      }@
+      }{}
      </tr>
-     @if{@isplaying}{
+     @playing{
      <tr class=nowplaying>
-      <td colspan=@if{@arg{mgmt}}{11}{7}@>@label{playing.now}</td>
+      <td colspan=@ifmanage{11}{7}>@label{playing.now}</td>
      </tr>
-     @playing{
      <tr class=playing>
-      <td class=when>@when@</td>
-      <td class=who>@if{@eq{@who@}{}@}{@if{@eq{@state@}{random}@}{@label{playing.randomtrack}}{&nbsp;}@}{@who@}@</td>
-      <td class=artist>@right{play}{<a class=directory
-       href="@url?action=choose&amp;directory=@urlquote{@dirname{@dirname{@part:path@}@}@}@"
-       title="@label{playing.artistverbose}"
-       >@part{short}{artist}@</a>}{<span class=directory
-       title="@part{artist}@"
-       >@part{short}{artist}@</span>}@</td>
-      <td class=album>@right{play}{<a class=directory
-       href="@url?action=choose&amp;directory=@urlquote{@dirname{@part:path@}@}@"
-       title="@label{playing.albumverbose}"
-       >@part{short}{album}@</a>}{<span class=directory
-       title="@part{album}@"
-       >@part{short}{album}@</span>}@</td>
-      <td class=title><span
-       title="@part{title}@">@part{short}{title}@</span></td>
-      <td class=length>@length@</td>
-      <td class=imgbutton>@if{@scratchable@}{<a class=imgbutton
-       href="@url?action=scratch&#38;id=@id@&#38;mgmt=@arg{mgmt}"><img
-       class=button src="@image{scratch}"
-       title="@label{playing.scratchverbose}"
-       alt="@label{playing.scratch}"></a>}{<img
-       class=button src="@image{noscratch}"
-       title="@label{playing.scratchverbose}"
-       alt="@label{playing.scratch}">}@</td>
-      @if{@arg{mgmt}}{
+      <td class=when>@when{@id}</td>
+      <td class=who>@if{@eq{@who{@id}}{}}
+                       {@if{@eq{@state{@id}}{random}}
+                           {@label{playing.randomtrack}}
+                           {&nbsp;}}
+                       {@who{@id}}
+      </td>
+      <td class=artist>@right{play}
+                             {<a class=directory
+                                 href="@url?action=choose&amp;directory=@urlquote{@dirname{@dirname{@track}}}"
+                                 title="@label{playing.artistverbose}">@part{@id}{short}{artist}</a>}
+                             {<span class=directory
+                                    title="@part{artist}@">@part{short}{artist}</span>}
+      </td>
+      <td class=album>@right{play}
+                            {<a class=directory
+                                href="@url?action=choose&amp;directory=@urlquote{@dirname{@track}}"
+                                title="@label{playing.albumverbose}">@part{short}{album}</a>}
+                            {<span class=directory
+                                   title="@part{album}@">@part{short}{album}</span>}
+      </td>
+      <td class=title><span title="@part{@id}{title}">@part{@id}{short}{title}</span></td>
+      <td class=length>@length{@id}</td>
+      <td class=imgbutton>@if{@removabl{@id}}
+                             {<a class=imgbutton
+                                 href="@url?action=scratch&#38;id=@id@back">
+                              <img class=button src="@image{scratch}"
+                                   title="@label{playing.scratchverbose}"
+                                   alt="@label{playing.scratch}"></a>}
+                             {<img class=button src="@image{noscratch}"
+                                   title="@label{playing.scratchverbose}"
+                                   alt="@label{playing.scratch}">}
+      </td>
+      @ifmanage{
       <td class=imgbutton>&nbsp;</td>
       <td class=imgbutton>&nbsp;</td>
       <td class=imgbutton>&nbsp;</td>
       <td class=imgbutton>&nbsp;</td>
-      }@
+      }{}
      </tr>
-     }@}@
+     }
      @if{@isqueue@}{
      <tr class=next>
-      <td colspan=@if{@arg{mgmt}}{11}{7}@>@label{playing.next}</td>
+      <td colspan=@ifmanage{11}{7}@>@label{playing.next}</td>
      </tr>
+     }
      @queue{
      <tr class=@parity@>
-      <td class=when>@when@</td>
-      <td class=who>@if{@eq{@who@}{}@}{@if{@eq{@state@}{random}@}{@label{queue.randomtrack}}{&nbsp;}@}{@who@}@</td>
+      <td class=when>@when</td>
+      <td class=who>@if{@eq{@who@}{}@}{@if{@eq{@state@}{random}@}{@label{queue.randomtrack}}{&nbsp;}@}{@who@}</td>
       <td class=artist>@right{play}{<a class=directory
-       title="@part{artist}@"
-       href="@url?action=choose&amp;directory=@urlquote{@dirname{@dirname{@part:path@}@}@}@"
-       >@part{short}{artist}@</a>}{<span class=directory
-       title="@part{artist}@"
-       >@part{short}{artist}@</span>}@</td>
+       title="@part{@id}{artist}@"
+       href="@url?action=choose&amp;directory=@urlquote{@dirname{@dirname{@track}@}@}@"
+       >@part{@id}{short}{artist}</a>}{<span class=directory
+       title="@part{@id}{artist}@"
+       >@part{@id}{short}{artist}</span>}</td>
       <td class=album>@right{play}{<a class=directory
-       title="@part{album}@"
-       href="@url?action=choose&amp;directory=@urlquote{@dirname{@part:path@}@}@"
-       >@part{short}{album}@</a>}{<span class=directory
-       title="@part{album}@"
-       >@part{short}{album}@}@</td>
+       title="@part{@id}{album}@"
+       href="@url?action=choose&amp;directory=@urlquote{@dirname{@track}@}@"
+       >@part{@id}{short}{album}</a>}{<span class=directory
+       title="@part{@id}{album}@"
+       >@part{@id}{short}{album}@}</td>
       <td class=title><span
-       title="@part{title}@">@part{short}{title}@</span></td>
-      <td class=length>@length@</td>
+       title="@part{@id}{title}@">@part{@id}{short}{title}</span></td>
+      <td class=length>@length</td>
       <td class=imgbutton>@if{@removable@}{<a class=imgbutton
-       href="@url?action=remove&#38;id=@id@&#38;mgmt=@arg{mgmt}"><img
+       href="@url?action=remove&#38;id=@id@@back"><img
        class=button src="@image{scratch}"
        title="@label{playing.removeverbose}" 
        alt="@label{playing.remove}"></a>}{<img
        class=button src="@image{noscratch}"
        title="@label{playing.removeverbose}"
-       alt="@label{playing.remove}">}@</td>
+       alt="@label{playing.remove}">}</td>
 
-      @if{@arg{mgmt}}{
+      @if{@eq{@arg{action}}{manage}}{
       @if{@or{@isfirst@}
              {@not{@movable@}@}@}{
      <!-- cannot move up -->
@@ -227,16 +244,16 @@ USA
      <!-- can move up -->
      <td class=imgbutton>
       <a class=imgbutton
-        href="@url?action=move&#38;id=@id@&#38;delta=2147483647&#38;mgmt=true"><img
+        href="@url?action=move&#38;id=@id@&#38;delta=2147483647@back"><img
        class=button src="@image{upall}"
        title="@label{playing.upallverbose}"
        alt="@label{playing.upall}"></a>
      <td class=imgbutton>
      <a class=imgbutton
-        href="@url?action=move&#38;id=@id@&#38;delta=1&#38;mgmt=true"><img
+        href="@url?action=move&#38;id=@id@&#38;delta=1@back"><img
        class=button src="@image{up}"
        title="@label{playing.upverbose}" alt="@label{playing.up}"></a>
-         }@
+         }
 
       @if{@or{@islast@}
              {@not{@movable@}@}@}{
@@ -253,32 +270,30 @@ USA
      <!-- can move down -->
      <td class=imgbutton>
       <a class=imgbutton
-        href="@url?action=move&#38;id=@id@&#38;delta=-2147483647&#38;mgmt=true"><img
+        href="@url?action=move&#38;id=@id@&#38;delta=-2147483647@back"><img
        class=button src="@image{downall}"
        title="@label{playing.downallverbose}"
        alt="@label{playing.downall}"></a>
      <td class=imgbutton>
      <a class=imgbutton
-        href="@url?action=move&#38;id=@id@&#38;delta=-1&#38;mgmt=true"><img
+        href="@url?action=move&#38;id=@id@&#38;delta=-1@back"><img
        class=button src="@image{down}"
        title="@label{playing.downverbose}" alt="@label{playing.down}"></a>
-         }@
-
-      }@
+         }
+      }
      </tr>
-     }@}@
+     }
    </table>
-}@
+}
 
-@include{topbarend}@
+@include{topbarend}@#
  </body>
 </html>
-@@
-<!--
+@discard{
 Local variables:
 mode:sgml
 sgml-always-quote-attributes:nil
 sgml-indent-step:1
 sgml-indent-data:t
 End:
--->
+}@
index e1a8174..9118ff1 100644 (file)
@@ -1,9 +1,6 @@
-@include:stylesheet@
-@@
-Anything that goes in all html HEAD elements goes here.
-<!--
+@discard{
 This file is part of DisOrder.
-Copyright (C) 2004 Richard Kettlewell
+Copyright (C) 2004, 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
@@ -19,4 +16,7 @@ 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
--->
+
+Anything that goes in all html HEAD elements goes here.
+}@#
+@include{stylesheet.tmpl}@#
index da58e56..da41aff 100644 (file)
@@ -1,8 +1,4 @@
-  <link rel=stylesheet type="text/css" href="@image:disorder.css@">
-@@
-This file is a standard place to put a link to a stylesheet,
-or an embedded stylesheet.
-<!--
+@discard{
 This file is part of DisOrder.
 Copyright (C) 2005, 2007, 2008 Richard Kettlewell
 
@@ -20,4 +16,10 @@ 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
--->
+
+This file is a standard place to put a link to a stylesheet,
+or an embedded stylesheet.
+}@#
+  <link rel=stylesheet
+        type="text/css"
+        href="@image{disorder.css}">