File: columnify.pike

package info (click to toggle)
libroxen-columnify 990120-4
  • links: PTS
  • area: main
  • in suites: woody
  • size: 32 kB
  • sloc: makefile: 36
file content (263 lines) | stat: -rw-r--r-- 6,796 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
/* this is a roxen module */
/* c burgess 20/1/99           */

/*
 * written to provide a means of producing nice catalogues from
 * sqlqueries without resorting to lunatic multiple queries :)
 *
 * you may experience unexpected results with some tables - for
 * instance, a vert cols=4 table where there are nine results will
 * give one empty column and three of three. this only seems to happen
 * where (rows < cols) && (rows = cols-1) ...
 * this is because it deduces the number of rows, then (effectively)
 * fills each row first. (that's not true, but it explains what
 * happens.)
 *
 * chris burgess, chris@ibex.co.nz, 20/1/99
 */

int thread_safe=1;

#include <module.h>
#include <simulate.h>
inherit "module";

// inherit "roxenlib";

// #define DEBUG

static private string doc()
{
  return "<tt>table, tr, td, (*)_end, emptycell</tt> args replace the specified tag with the argument value.<br>" + 
    "<tt>sep</tt> defines the separator (default |)<br>" + 
    "<tt>cols</tt> defines the number of columns to create<br>" +
    "<tt>vert</tt> specifies that values should be arranged down then across";
}

void create() {  
	defvar("debug", 
		   1,
		   "Show errors in pages",
		   TYPE_FLAG,
		   "Whether to show errors when things go awry."
		   );
	defvar("emptycell", 
		   "&nbsp;",
		   "Empty cell value",
		   TYPE_STRING,
		   "HTML of any empty cell in the returned table, eg '<tt>&amp;nbsp;</tt>'.");
	defvar("td_end", 
		   "</td>",
		   "Table cell close",
		   TYPE_STRING,
		   "HTML used to close a table cell, eg '<tt>&lt;/td&gt;");
	defvar("td", 
		   "<td align=\"left\" valign=\"top\">",
		   "Table cell open",
		   TYPE_STRING,
		   "HTML used to open a table cell, eg '<tt>&lt;td&gt;");
	defvar("tr_end", 
		   "</tr>",
		   "Table row end",
		   TYPE_STRING,
		   "HTML used to end a table row, eg '<tt>&lt;/tr&gt;");
	defvar("tr",
		   "<tr>",
		   "Table row start",
		   TYPE_STRING,
		   "HTML used to start a table row, eg '<tt>&lt;tr&gt;");
	defvar("table_end", 
		   "</table>",
		   "Table end",
		   TYPE_STRING,
		   "HTML used to end a table, eg '<tt>&lt;/table&gt;");
	defvar("table", 
		   "<table>",
		   "Table start",
		   TYPE_STRING,
		   "HTML used to begin a table, eg '<tt>&lt;table&gt;");
}


array register_module()
{
	return ({ MODULE_PARSER, 
              "Columnify Module",
              "This module makes columns using the container <tt>&lt;columnify&gt; &lt;/columnify&gt;</tt> "
              "and the separator <tt>&lt;cell&gt;</tt>. It actually makes tables, but the function is more column "
              "oriented, hence the silly name. Also, there is already a <tt>&lt;tablify&gt;</tt> tag which does "
              "a completely different thing.<p>" + doc(),
              ({ }),
              1
    });
}

string container_columnify(string tag_name, mapping args, string contents, object request_id, mapping defines) {

	/*
	 * result is end result returned
	 * sep is the separator, taken from an arg or default "|"
	 * table, tr, td and (*)_end and emptycell defvars or args for table format
	 * cols is an arg or defvar, rows is calculated from contents/cols rounded up
	 * (*)_cells are the contents arrays
	 */
	string result,sep,table,table_end,td,td_end,tr,tr_end,emptycell,tmp = "";
	int cols,rows;
	string *blank_cells, *content_cells, *all_cells;

	string debug = "";

	// some defaults, called from defvars now
	emptycell = (args->emptycell||query("emptycell"));
	td = (args->td||query("td"));
	td_end = (args->td_end||query("td_end"))+ "\n";
	tr = (args->tr||query("tr")) + "\n";
	tr_end = (args->tr_end||query("tr_end")) + "\n";
	table = (args->table||query("table")) + "\n";
	table_end = (args->table_end||query("table_end")) + "\n";

	result = "";

	// decide on separator and make array of cell contents
	if (!(args->sep))
		sep = "|";
	else
		sep = args->sep;
	content_cells = contents/sep;

	if(query("debug"))
	  debug += "content_cells = " + sizeof(content_cells) + "\n";

	// optionally delete 'blank' content_cells - good for sqloutput where sep
	// can go before </sqloutput> and produce empty final cell
	if (args->trim) {
		content_cells -= ({"","\n"," "});
	}

	// cols is either arg or 2
	if (!(int)(args->cols))
		cols = 2;
	else
		cols = (int)args->cols;

	if(query("debug"))
	  debug += "cols = " + cols + "\n";

	// get float of rows, make into int rounded up
	float f_cols;
	f_cols = 0.0 + cols;
	float f_rows = (sizeof(content_cells)/f_cols);
	int rows = (int)f_rows;
	if (rows < f_rows)
		rows++;

	if(query("debug"))
	  debug += "rows = " + rows + "\n";

	// create array of blank cells to pad empty table cells
	// more useful for vert than horz but still a good idea
	int num_blank_cells = (( cols * rows ) - sizeof(content_cells));
	blank_cells = allocate(num_blank_cells);
	for ( int i = 0 ; i < num_blank_cells ; i++ ) {
		blank_cells[i] = emptycell;
	}

	if(query("debug"))
	  debug += "blank_cells = " + sizeof(blank_cells) + "\n";

	// now create array of content + blank cells
	all_cells = (content_cells + blank_cells);

	if(query("debug"))
	  debug += "all_cells = " + sizeof(all_cells) + "\norder:";

	// open the table
	result += table;

	// for each row ...
	for ( int r = 0 ; r < rows ; r++ ) {
	  tmp += tr;
	  // for each column ...
	  for ( int c = 0 ; c < cols ; c++ ) {
		tmp += td;
		if (args->vert)
		  tmp += all_cells[rows*c+r];
		else
		  tmp += all_cells[cols*r+c];
		tmp += td_end;

		if(query("debug"))
		  if (args->vert)
			debug += rows*c+r + " ";
		  else
			debug += cols*r+c + " ";

	  }
	  tmp += tr_end;
	}

	if(query("debug"))
	  debug += "\n";

	result += tmp;
	
	if(query("debug"))
	  debug += sprintf("%O",all_cells);
	
	result += table_end;

	if (debug)
	  report_error(debug);

	if (debug)
	  request_id->variables->debug = debug;

	return result;

}

// This is nessesary functions for all MODULE_PARSER modules.
mapping query_container_callers() { 
	return( ([ "columnify": container_columnify ]) );
}

// 	if (!args->vert) {
// 		// for each col

// 		for ( int i = 0; i < (sizeof(all_cells)-1); i++ ) {
// 			// append tr tags at row start & end
// 			if ( i % cols == 0 )
// 				tmp = tr + td;
// 			else
// 				tmp = td;
// 				tmp += all_cells[i];
// 			if ( (i+1) % cols == 0 )
// 				tmp += td_end + tr_end;
// 			else
// 				tmp += td_end;
// 			result += tmp;
// 			}
// 		result += tmp;

// 		if(query("debug"))
// 		  debug += "vertical\n";

// 	} else {
// 		// for each row ...
// 		for ( int r = 0 ; r < rows ; r++ ) {
// 			tmp += tr;
// 			// for each column ...
// 			for ( int c = 0 ; c < cols ; c++ ) {
// 				tmp += td;
// 				int e = ((rows)*c+r);
// 				tmp += all_cells[e];
// 				tmp += td_end;
// 			}
// 			tmp += tr_end;
// 		}
// 		result += tmp;

// 		if(query("debug"))
// 		  debug += "horiz\n";

// 	}