change first parameter for object display functions
[webgit] / src / object.c
index 4d3597eaec93e5dc1fc00e40326430f2138fb3b9..6e0679ee40f8d5ba61ee2e60a0c4f8526493ac3d 100644 (file)
 */
 
 #include "object.h"
-
-#define SHA1_HEADER <openssl/sha.h>
-#include "git/git-compat-util.h"
-#include "git/object.h"
+#include "repo.h"
 
 
 Html
-ctgit_object_link (struct ctgit_query* query,
-                   const char* repo,
-                   int repo_len,
-                   const char* object,
-                   int object_len,
-                   Html text)
+webgit_object_link (struct webgit_query* query,
+                    const char* repo,
+                    int repo_len,
+                    const char* object,
+                    int object_len,
+                    const char* path,
+                    const char* action,
+                    Html text)
 {
   return html (
                html_tag ("a",
-                         html_attr ("href", html_fmt ("%s?repo=%.*s&object=%.*s",
-                                                      query->request->script_name,
-                                                      repo_len, repo,
-                                                      object_len, object)
+                         html_attr ("href", html (
+                                                  html_fmt ("%s?repo=%.*s&object=%.*s",
+                                                            query->request->script_name,
+                                                            repo_len, repo,
+                                                            object_len, object),
+                                                  path ? html_fmt ("&path=%s", path) : html (),
+                                                  action ? html_fmt ("&action=%s", action) : html ()
+                                                  )
                                     )
                          ),
                text
@@ -47,19 +50,182 @@ ctgit_object_link (struct ctgit_query* query,
 }
 
 
+
+char*
+webgit_commit_tree_parse (struct commit* commit)
+{
+  char* tree = strstr (commit->buffer, "tree ");
+  if (!tree)
+    return NULL;
+  return tree + 5;
+}
+
+time_t
+webgit_commit_author_date_parse (struct commit* commit, struct tm* tm)
+{
+  struct tm tmp;
+  if (!tm)
+    tm = &tmp;
+
+  char* author = strstr (commit->buffer, "author ");
+  if (!author)
+    return (time_t)-1;
+
+  char* beg = strchr (author, '>');
+  if (!beg)
+    return (time_t)-1;
+
+  if (!strptime (beg + 2, "%s %Z", tm))
+    return (time_t)-1;
+
+  return mktime (tm);
+}
+
+Html
+webgit_commit_author_name_parse (struct commit* commit)
+{
+  char* author = strstr (commit->buffer, "author ");
+  if (!author)
+    return NULL;
+
+  char* end = strchr (author, '<');
+  if (!end)
+    return NULL;
+
+  return html_fmt ("%.*s", end-author-8, author+7);
+}
+
+Html
+webgit_commit_author_email_parse (struct commit* commit)
+{
+  char* author = strstr (commit->buffer, "author ");
+  if (!author)
+    return NULL;
+
+  char* beg = strchr (author, '<');
+  if (!beg)
+    return NULL;
+
+  char* end = strchr (beg, '>');
+  if (!end)
+    return NULL;
+
+
+  return html_fmt ("%.*s", end-beg-1, beg+1);
+}
+
+time_t
+webgit_commit_committer_date_parse (struct commit* commit, struct tm* tm)
+{
+  struct tm tmp;
+  if (!tm)
+    tm = &tmp;
+
+  char* committer = strstr (commit->buffer, "committer ");
+  if (!committer)
+    return (time_t)-1;
+
+  char* beg = strchr (committer, '>');
+  if (!beg)
+    return (time_t)-1;
+
+  if (!strptime (beg + 2, "%s %Z", tm))
+    return (time_t)-1;
+
+  return mktime (tm);
+}
+
+Html
+webgit_commit_committer_name_parse (struct commit* commit)
+{
+  char* committer = strstr (commit->buffer, "committer ");
+  if (!committer)
+    return NULL;
+
+  char* end = strchr (committer, '<');
+  if (!end)
+    return NULL;
+
+  return html_fmt ("%.*s", end-committer-11, committer+10);
+}
+
+Html
+webgit_commit_committer_email_parse (struct commit* commit)
+{
+  char* committer = strstr (commit->buffer, "committer ");
+  if (!committer)
+    return NULL;
+
+  char* beg = strchr (committer, '<');
+  if (!beg)
+    return NULL;
+
+  char* end = strchr (beg, '>');
+  if (!end)
+    return NULL;
+
+
+  return html_fmt ("%.*s", end-beg-1, beg+1);
+}
+
+Html
+webgit_commit_header_parse (struct commit* commit)
+{
+  char* header = strstr (commit->buffer, "\n\n");
+  if (!header)
+    return NULL;
+
+  char* end = strchr (header+2, '\n');
+  if (!end)
+    end = header + strlen (header+2);
+  else
+    --end;
+
+  return html_fmt ("%.*s", end-header, header+2);
+}
+
+Html
+webgit_commit_message_parse (struct commit* commit)
+{
+  char* header = strstr (commit->buffer, "\n\n");
+  if (!header)
+    return NULL;
+
+  header = strchr (header+2, '\n');
+  if (!header)
+    return html ();
+  else
+    ++header;
+
+  return html_fmt ("%.*s", strlen (header), header);
+}
+
+
+
+
 /*
-  Display committs
+  Display commits
 */
 
 static Html
-ctgit_object_commit_menu_action (struct ctgit_query* query, unsigned char* sha1, void* buf, unsigned long size)
+webgit_object_commit_menu_action (struct webgit_repo_info* repo, unsigned char* sha1, void* buf, unsigned long size)
 {
+  (void) repo;
+  (void) sha1;
+  (void) buf;
+  (void) size;
+
   return html ("TODO: commit-object sidebar");
 }
 
 static Html
-ctgit_object_commit_content_action (struct ctgit_query* query, unsigned char* sha1, void* buf, unsigned long size)
+webgit_object_commit_content_action (struct webgit_repo_info* repo, unsigned char* sha1, void* buf, unsigned long size)
 {
+/*
+  TODO pass commit objects instead buf/size, use parsers from above
+*/
+  (void) sha1;
+
   Html tree = html_list ();
   Html parents = html_list ();
   Html author_text = html_list ();
@@ -70,7 +236,7 @@ ctgit_object_commit_content_action (struct ctgit_query* query, unsigned char* sh
   const char* author_end = NULL;
 
   const char* i = buf;
-  while (i && i < buf+size)
+  while (i && (void*)i < buf+size)
     {
       if (*i == '\n')
         {
@@ -80,29 +246,33 @@ ctgit_object_commit_content_action (struct ctgit_query* query, unsigned char* sh
         }
       if (!strncmp (i, "tree ", 5))
         {
-
           html_list_append (tree,
                             "Tree: ",
-                            ctgit_object_link (query,
-                                               query->repo, strlen (query->repo),
-                                               i+5, 40,
-                                               html_fmt ("%.40s", i+5))
+                            webgit_object_link (repo->query,
+                                                repo->name, strlen (repo->name),
+                                                i+5, 40,
+                                                NULL,
+                                                NULL,
+                                                html_fmt ("%.40s", i+5))
                             );
-
-          (i = strchr (i, '\n')) && ++i;
+          if ((i = strchr (i, '\n')))
+            ++i;
           continue;
         }
       else if (!strncmp (i, "parent ", 7))
         {
           html_list_append (parents, html (
                                            "Parent: ",
-                                           ctgit_object_link (query,
-                                                              query->repo, strlen (query->repo),
-                                                              i+7, 40,
-                                                              html_fmt ("%.40s", i+7))
+                                           webgit_object_link (repo->query,
+                                                               repo->name, strlen (repo->name),
+                                                               i+7, 40,
+                                                               NULL,
+                                                               NULL,
+                                                               html_fmt ("%.40s", i+7))
                                            )
                             );
-          (i = strchr (i, '\n')) && ++i;
+          if ((i = strchr (i, '\n')))
+            ++i;
           continue;
         }
       else if (!strncmp (i, "author ", 7))
@@ -125,17 +295,12 @@ ctgit_object_commit_content_action (struct ctgit_query* query, unsigned char* sh
 
           html_list_append (author, html (
                                           html ( author_text ), /*BUG: libcwa bug, must be wraped in html()*/
-                                          html (
-                                                html_tag("a",
-                                                         html_attr ("href",
-                                                                    html ("mailto:", email))
-                                                         ),
-                                                name
-                                                ),
+                                          webgit_email_link (name, email),
                                           html_strndup (pretty_date, 255)
                                           )
                             );
-          (i = strchr (i, '\n')) && ++i;
+          if ((i = strchr (i, '\n')))
+            ++i;
           continue;
         }
       else if (!strncmp (i, "committer ", 10))
@@ -154,13 +319,7 @@ ctgit_object_commit_content_action (struct ctgit_query* query, unsigned char* sh
               strftime (pretty_date, 255, "%c", &tm);
 
               html_list_append (committer, html ("Committer: ",
-                                                 html(
-                                                      html_tag("a",
-                                                               html_attr("href",
-                                                                         html ("mailto:", email))
-                                                               ),
-                                                      name
-                                                      ),
+                                                 webgit_email_link (name, email),
                                                  html_strndup (pretty_date, 255)
                                                  )
                                 );
@@ -168,7 +327,8 @@ ctgit_object_commit_content_action (struct ctgit_query* query, unsigned char* sh
           else
             html_list_append (author_text, " and Committer");
 
-          (i = strchr (i, '\n')) && ++i;
+          if ((i = strchr (i, '\n')))
+            ++i;
           continue;
         }
       ++i;
@@ -176,8 +336,6 @@ ctgit_object_commit_content_action (struct ctgit_query* query, unsigned char* sh
 
   html_list_append (author_text, ": ");
 
-
-
   Html headline = html_list ();
   Html message = html_list ();
 
@@ -209,7 +367,7 @@ ctgit_object_commit_content_action (struct ctgit_query* query, unsigned char* sh
         }
     }
 
-  /* diffstat */
+  /* TODO: diffstat */
 
 
   return html (
@@ -223,7 +381,7 @@ ctgit_object_commit_content_action (struct ctgit_query* query, unsigned char* sh
 }
 
 Html
-ctgit_object_commit_action (struct ctgit_query* query, unsigned char* sha1)
+webgit_object_commit_action (struct webgit_repo_info* repo, unsigned char* sha1)
 {
   void* buf;
   unsigned long size;
@@ -231,45 +389,228 @@ ctgit_object_commit_action (struct ctgit_query* query, unsigned char* sha1)
   buf = read_object_with_reference (sha1, "commit", &size, NULL);
 
   return html(
-              html(html_tag("div"), ctgit_object_commit_menu_action (query, sha1, buf, size)), html_nl (),
-              html(html_tag("div"), ctgit_object_commit_content_action (query, sha1, buf, size)), html_nl ()
+              html(html_tag("div"), webgit_object_commit_menu_action (repo, sha1, buf, size)), html_nl (),
+              html(html_tag("div"), webgit_object_commit_content_action (repo, sha1, buf, size)), html_nl ()
               );
 }
 
 
+/*
+  Display trees
+*/
 
+static Html
+webgit_object_tree_menu_action (struct webgit_repo_info* repo, unsigned char* sha1, struct tree *tree)
+{
+  (void) repo;
+  (void) sha1;
+  (void) tree;
+  return html ("TODO: tree-object sidebar");
+}
 
+static const char*
+pretty_mode (unsigned mode)
+{
+  if (S_ISGITLINK (mode))
+    return "m---------";
+  else if (S_ISDIR (mode & S_IFMT))
+    return "drwxr-xr-x";
+  else if (S_ISLNK (mode))
+    return "lrwxrwxrwx";
+  else if (S_ISREG (mode))
+    {
+      if (mode & S_IXUSR)
+        return "-rwxr-xr-x";
+      else
+        return "-rw-r--r--";
+    }
+  else
+    return "----------";
+}
 
+/* callback has no user-data pointer! */
+static struct webgit_query* query_in_flight = NULL;
+static Html tree_in_flight = NULL;
 
+static int
+webgit_html_tree (const unsigned char *sha1, const char *base, int baselen,
+                  const char *name, unsigned mode, int stage)
+{
+  (void) stage;
+  char pathname[PATH_MAX];
 
+  snprintf (pathname, PATH_MAX-1, "%.*s%s%s", baselen, base, baselen ? "/": "", name);
 
+  if (S_ISGITLINK(mode))
+    {
+      html_list_append (tree_in_flight, html (
+                                              html (
+                                                    html_tag ("tr"),
+                                                    html (html_tag ("td"), pretty_mode (mode)),
+                                                    html (html_tag ("td"),
+                                                          webgit_repo_link (query_in_flight,
+                                                                            query_in_flight->repo,
+                                                                            strlen (query_in_flight->repo),
+                                                                            name, strlen (pathname),
+                                                                            sha1_to_hex (sha1), 40,
+                                                                            "tree",
+                                                                            html_strndup (pathname, SIZE_MAX))
+                                                          ),
+                                                    html (html_tag ("td"), "history summary")
+                                                    ),
+                                              html_nl ()
+                                              )
+                        );
+    }
+  else if (S_ISDIR(mode))
+    {
+      html_list_append (tree_in_flight, html (
+                                              html (html_tag ("tr"),
+                                                    html (html_tag ("td"), pretty_mode (mode)),
+                                                    html (html_tag ("td"),
+                                                          webgit_object_link (query_in_flight,
+                                                                              query_in_flight->repo,
+                                                                              strlen (query_in_flight->repo),
+                                                                              sha1_to_hex (sha1), 40,
+                                                                              pathname,
+                                                                              NULL,
+                                                                              html_strndup (name, SIZE_MAX))
+                                                          ),
+                                                  html (html_tag ("td"), "history snap")
+                                                  ),
+                                             html_nl ()
+                                             )
+                        );
+    }
+  else
+    {
+      html_list_append (tree_in_flight, html (
+                                              html (html_tag ("tr"),
+                                                    html (html_tag ("td"), pretty_mode (mode)),
+                                                    html (html_tag ("td"),
+                                                          webgit_object_link (query_in_flight,
+                                                                              query_in_flight->repo,
+                                                                              strlen (query_in_flight->repo),
+                                                                              sha1_to_hex (sha1), 40,
+                                                                              pathname,
+                                                                              NULL,
+                                                                              html_strndup (name, SIZE_MAX))
+                                                          ),
+                                                    html (html_tag ("td"),
+                                                          "history ",
+                                                          webgit_object_link (query_in_flight,
+                                                                              query_in_flight->repo,
+                                                                              strlen (query_in_flight->repo),
+                                                                              sha1_to_hex (sha1), 40,
+                                                                              pathname,
+                                                                              "raw",
+                                                                              html ("raw")),
+                                                          " edit")
+                                                    ),
+                                              html_nl()
+                                              )
+                        );
+    }
 
+  return 0;
+}
 
 
+static Html
+webgit_object_tree_content_action (struct webgit_repo_info* repo, unsigned char* sha1, struct tree *tree)
+{
+  (void) sha1;
+  query_in_flight = repo->query;
+  tree_in_flight = html_list ();
 
+  read_tree_recursive (tree, repo->query->path,
+                       repo->query->path ? strlen (repo->query->path) : 0, 0, NULL, webgit_html_tree);
+
+  return html (html_tag ("table"), tree_in_flight);
+}
+
+Html
+webgit_object_tree_action (struct webgit_repo_info* repo, unsigned char* sha1)
+{
+  struct tree *tree;
+
+  tree = parse_tree_indirect (sha1);
+  if (!tree)
+    die("not a tree object");
+
+  return html(
+              html(html_tag("div"), webgit_object_tree_menu_action (repo, sha1, tree)), html_nl (),
+              html(html_tag("div"), webgit_object_tree_content_action (repo, sha1, tree)), html_nl ()
+              );
+}
+
+
+/*
+  Display blobs
+*/
 static Html
-ctgit_object_tree_menu_action (struct ctgit_query* query, unsigned char* sha1, void* buf, unsigned long size)
+webgit_object_blob_menu_action (struct webgit_repo_info* repo, unsigned char* sha1, void* buf, unsigned long size)
 {
-  return html ("TODO: tree-object sidebar");
+  (void) repo;
+  (void) sha1;
+  (void) buf;
+  (void) size;
+  return html ("TODO: blob-object sidebar");
 }
 
 static Html
-ctgit_object_tree_content_action (struct ctgit_query* query, unsigned char* sha1, void* buf, unsigned long size)
+webgit_object_blob_content_action (struct webgit_repo_info* repo, unsigned char* sha1, void* buf, unsigned long size)
 {
+  (void) sha1;
 
-  return html_fmt ("tree content %s", buf);
+  if (!memchr(buf, 0, size>8192 ? 8192 : size))
+    {
+      return html (html_tag ("pre"), html_strndup (buf, size));
+    }
+  else
+    {
+      struct webgit_query* query = repo->query;
+      const char* mimetype = webgit_mimetype (query->path);
+
+      Html ret;
+
+      if (mimetype && !strncmp(mimetype, "image/", 6))
+        {
+          /* inline image */
+          ret = html (
+                      html_tag ("img",
+                                html_attr ("src",
+                                           html_fmt ("%s?repo=%s&action=raw&object=%s&path=%s",
+                                                     query->request->script_name,
+                                                     query->repo, query->object, query->path)
+                                           ),
+                                html_attr ("alt", query->path ? query->path : query->object)
+                                )
+                      );
+        }
+      else
+        {
+          /* link to raw data */
+          ret = html ("binary blob");
+        }
+      free ((char*)mimetype);
+
+      return ret;
+    }
 }
 
+
 Html
-ctgit_object_tree_action (struct ctgit_query* query, unsigned char* sha1)
+webgit_object_blob_action (struct webgit_repo_info* repo, unsigned char* sha1)
 {
-  unsigned long size;
   void* buf;
-  buf = read_object_with_reference (sha1, "tree", &size, NULL);
+  unsigned long size;
+
+  buf = read_object_with_reference (sha1, "blob", &size, NULL);
 
   return html(
-              html(html_tag("div"), ctgit_object_tree_menu_action (query, sha1, buf, size)), html_nl (),
-              html(html_tag("div"), ctgit_object_tree_content_action (query, sha1, buf, size)), html_nl ()
+              html(html_tag("div"), webgit_object_blob_menu_action (repo, sha1, buf, size)), html_nl (),
+              html(html_tag("div"), webgit_object_blob_content_action (repo, sha1, buf, size)), html_nl ()
               );
 }
 
@@ -278,4 +619,4 @@ ctgit_object_tree_action (struct ctgit_query* query, unsigned char* sha1)
 
 /*pretty printer for sourcecode*/
 //Html
-//ctgit_object_blob_dispatch (struct ctgit_query* query, const char *sha1);
+//webgit_object_blob_dispatch (struct webgit_query* query, const char *sha1);