]> gitweb.ps.run Git - ps-cgit/blob - ui-tree.c
ui-tree: make blob viewer generate valid html
[ps-cgit] / ui-tree.c
1 /* ui-tree.c: functions for tree output
2  *
3  * Copyright (C) 2006 Lars Hjemli
4  *
5  * Licensed under GNU General Public License v2
6  *   (see COPYING for full license text)
7  */
8
9 #include "cgit.h"
10
11 char *curr_rev;
12 char *match_path;
13 int header = 0;
14
15 static void print_object(const unsigned char *sha1, char *path)
16 {
17         enum object_type type;
18         unsigned char *buf;
19         unsigned long size, lineno, start, idx;
20
21         type = sha1_object_info(sha1, &size);
22         if (type == OBJ_BAD) {
23                 cgit_print_error(fmt("Bad object name: %s",
24                                      sha1_to_hex(sha1)));
25                 return;
26         }
27
28         buf = read_sha1_file(sha1, &type, &size);
29         if (!buf) {
30                 cgit_print_error(fmt("Error reading object %s",
31                                      sha1_to_hex(sha1)));
32                 return;
33         }
34
35         html("<table class='blob'>\n");
36         idx = 0;
37         start = 0;
38         lineno = 0;
39         while(idx < size) {
40                 if (buf[idx] == '\n') {
41                         buf[idx] = '\0';
42                         htmlf("<tr><td class='no'>%d</td><td class='txt'>",
43                               ++lineno);
44                         html_txt(buf + start);
45                         html("</td></tr>\n");
46                         start = idx + 1;
47                 }
48                 idx++;
49         }
50         html("</table>\n");
51 }
52
53
54 static int ls_item(const unsigned char *sha1, const char *base, int baselen,
55                    const char *pathname, unsigned int mode, int stage)
56 {
57         char *name;
58         enum object_type type;
59         unsigned long size = 0;
60         char *url, *qry;
61
62         name = xstrdup(pathname);
63         type = sha1_object_info(sha1, &size);
64         if (type == OBJ_BAD && !S_ISDIRLNK(mode)) {
65                 htmlf("<tr><td colspan='3'>Bad object: %s %s</td></tr>",
66                       name,
67                       sha1_to_hex(sha1));
68                 return 0;
69         }
70         qry = fmt("h=%s&amp;path=%s%s%s", curr_rev,
71                   cgit_query_path ? cgit_query_path : "",
72                   cgit_query_path ? "/" : "", pathname);
73         url = cgit_pageurl(cgit_query_repo, "tree", qry);
74         html("<tr><td class='filemode'>");
75         html_filemode(mode);
76         html("</td><td ");
77         if (S_ISDIRLNK(mode)) {
78                 htmlf("class='ls-mod'><a href='");
79                 html_attr(fmt(cgit_repo->module_link,
80                               name,
81                               sha1_to_hex(sha1)));
82         } else if (S_ISDIR(mode)) {
83                 html("class='ls-dir'><a href='");
84                 html_attr(url);
85         } else {
86                 html("class='ls-blob'><a href='");
87                 html_attr(url);
88         }
89         htmlf("'>%s</a></td>", name);
90         htmlf("<td class='filesize'>%li</td>", size);
91
92         html("<td class='links'><a href='");
93         qry = fmt("h=%s&amp;path=%s%s%s", curr_rev,
94                   cgit_query_path ? cgit_query_path : "",
95                   cgit_query_path ? "/" : "", pathname);
96         url = cgit_pageurl(cgit_query_repo, "log", qry);
97         html_attr(url);
98         html("' class='button'>H</a></td>");
99         html("</tr>\n");
100         free(name);
101         return 0;
102 }
103
104 static void ls_head()
105 {
106         html("<table class='list'>\n");
107         html("<tr class='nohover'>");
108         html("<th class='left'>Mode</th>");
109         html("<th class='left'>Name</th>");
110         html("<th class='right'>Size</th>");
111         html("<th/>");
112         html("</tr>\n");
113         header = 1;
114 }
115
116 static void ls_tail()
117 {
118         if (!header)
119                 return;
120         html("</table>\n");
121         header = 0;
122 }
123
124 static void ls_tree(const unsigned char *sha1, char *path)
125 {
126         struct tree *tree;
127
128         tree = parse_tree_indirect(sha1);
129         if (!tree) {
130                 cgit_print_error(fmt("Not a tree object: %s",
131                                      sha1_to_hex(sha1)));
132                 return;
133         }
134
135         ls_head();
136         read_tree_recursive(tree, "", 0, 1, NULL, ls_item);
137         ls_tail();
138 }
139
140
141 static int walk_tree(const unsigned char *sha1, const char *base, int baselen,
142                      const char *pathname, unsigned mode, int stage)
143 {
144         static int state;
145         static char buffer[PATH_MAX];
146         char *url;
147
148         if (state == 0) {
149                 memcpy(buffer, base, baselen);
150                 strcpy(buffer+baselen, pathname);
151                 url = cgit_pageurl(cgit_query_repo, "tree",
152                                    fmt("h=%s&amp;path=%s", curr_rev, buffer));
153                 htmlf(" / <a href='");
154                 html_attr(url);
155                 html("'>");
156                 html_txt(xstrdup(pathname));
157                 html("</a>");
158
159                 if (strcmp(match_path, buffer))
160                         return READ_TREE_RECURSIVE;
161
162                 if (S_ISDIR(mode)) {
163                         state = 1;
164                         ls_head();
165                         return READ_TREE_RECURSIVE;
166                 } else {
167                         print_object(sha1, buffer);
168                         return 0;
169                 }
170         }
171         ls_item(sha1, base, baselen, pathname, mode, stage);
172         return 0;
173 }
174
175
176 /*
177  * Show a tree or a blob
178  *   rev:  the commit pointing at the root tree object
179  *   path: path to tree or blob
180  */
181 void cgit_print_tree(const char *rev, char *path)
182 {
183         unsigned char sha1[20];
184         struct commit *commit;
185         const char *paths[] = {path, NULL};
186
187         if (!rev)
188                 rev = cgit_query_head;
189
190         curr_rev = xstrdup(rev);
191         if (get_sha1(rev, sha1)) {
192                 cgit_print_error(fmt("Invalid revision name: %s", rev));
193                 return;
194         }
195         commit = lookup_commit_reference(sha1);
196         if (!commit || parse_commit(commit)) {
197                 cgit_print_error(fmt("Invalid commit reference: %s", rev));
198                 return;
199         }
200
201         html("path: <a href='");
202         html_attr(cgit_pageurl(cgit_query_repo, "tree", fmt("h=%s", rev)));
203         html("'>root</a>");
204
205         if (path == NULL) {
206                 ls_tree(commit->tree->object.sha1, NULL);
207                 return;
208         }
209
210         match_path = path;
211         read_tree_recursive(commit->tree, NULL, 0, 0, paths, walk_tree);
212         ls_tail();
213 }