btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / add-ons / kernel / debugger / qrencode / module.cpp
blobb2f215ddce2a656d420fff178971edbbb197f4c7
1 /*
2 * Copyright 2012, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Michael Lotz <mmlr@mlotz.ch>
7 */
10 #include <debug.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
15 extern "C" {
16 #include "qrencode.h"
17 #include "qrspec.h"
21 extern "C" {
22 extern void abort_debugger_command();
26 static const char* kWebPostBaseURL = "http://mlotz.ch/q";
28 static char sStringBuffer[16 * 1024];
29 static char sEncodeBuffer[3 * 1024];
30 static int sBufferPosition = 0;
31 static int sQRCodeVersion = 19;
32 static QRecLevel sQRCodeLevel = QR_ECLEVEL_L;
33 static char sWebPostId[64];
34 static int sWebPostCounter = 0;
37 static bool
38 qrcode_bit(QRcode* qrCode, int x, int y)
40 if (x >= qrCode->width || y >= qrCode->width)
41 return false;
43 return (qrCode->data[y * qrCode->width + x] & 0x01) == 1;
47 static void
48 move_to_and_clear_line(int line)
50 kprintf(" \x1b[%dd\x1b[G\x1b[K", line + 1);
54 static bool
55 print_qrcode(QRcode* qrCode, bool waitForKey)
57 move_to_and_clear_line(0);
58 for (int y = 0; y < qrCode->width; y += 2) {
59 move_to_and_clear_line(y / 2 + 1);
60 kputs(" ");
62 for (int x = 0; x < qrCode->width; x++) {
63 bool upper = qrcode_bit(qrCode, x, y);
64 bool lower = qrcode_bit(qrCode, x, y + 1);
65 if (upper == lower)
66 kputs(upper ? "\x11" : " ");
67 else
68 kputs(upper ? "\x12" : "\x13");
72 move_to_and_clear_line(qrCode->width / 2 + 2);
73 move_to_and_clear_line(qrCode->width / 2 + 3);
75 if (waitForKey) {
76 kputs("press q to abort or any other key to continue...\x1b[1B\x1b[G");
77 if (kgetc() == 'q')
78 return false;
81 return true;
85 static int
86 encode_url(const char* query, const char* data, int encodeLength,
87 int inputLength)
89 sEncodeBuffer[0] = 0;
90 strlcat(sEncodeBuffer, kWebPostBaseURL, encodeLength + 1);
91 strlcat(sEncodeBuffer, "?i=", encodeLength + 1);
92 strlcat(sEncodeBuffer, sWebPostId, encodeLength + 1);
93 strlcat(sEncodeBuffer, "&", encodeLength + 1);
94 strlcat(sEncodeBuffer, query, encodeLength + 1);
95 int position = strlcat(sEncodeBuffer, "=", encodeLength + 1);
96 if (position > encodeLength)
97 return -1;
99 int copyCount = 0;
100 while (inputLength > 0 && position < encodeLength) {
101 char character = data[copyCount];
102 if ((character >= 'a' && character <= 'z')
103 || (character >= 'A' && character <= 'Z')
104 || (character >= '0' && character <= '9')
105 || character == '.' || character == '-' || character == '_'
106 || character == '~'
107 // These aren't strictly valid, but seem to work.
108 || character == '/' || character == '(' || character == ')'
109 || character == '=' || character == '^' || character == '?'
110 || character == '|' || character == '*' || character == '@'
111 || character == ';' || character == ':' || character == ','
112 || character == '{' || character == '}' || character == '['
113 || character == ']' || character == '<' || character == '>'
114 || character == '!' || character == '\\') {
115 sEncodeBuffer[position++] = character;
116 sEncodeBuffer[position] = 0;
117 } else if (character == ' ') {
118 // Encode spaces as '+' as that's shorter than %20.
119 sEncodeBuffer[position++] = '+';
120 sEncodeBuffer[position] = 0;
121 } else {
122 // Encode to a %xx escape.
123 if (encodeLength - position < 3) {
124 // Doesn't fit anymore, we're done.
125 break;
128 char escaped[4];
129 sprintf(escaped, "%%%.2x", character);
130 position = strlcat(sEncodeBuffer, escaped, encodeLength + 1);
133 inputLength--;
134 copyCount++;
137 return copyCount;
141 static int
142 qrencode(int argc, char* argv[])
144 if (argc > 1 && strcmp(argv[1], "--help") == 0) {
145 kprintf("%s [<string>]\n", argv[0]);
146 kprintf("If an argument is given, encodes that string as a QR code.\n"
147 "Otherwise the current QR buffer is encoded as QR codes.\n"
148 "When encoding from the QR buffer, the buffer is left intact.\n"
149 "use qrclear to clear the QR buffer or qrflush to encode/clear.\n");
150 return 1;
153 const char* source = NULL;
154 if (argc < 2) {
155 sStringBuffer[sBufferPosition] = 0;
156 source = sStringBuffer;
157 } else
158 source = argv[1];
160 int inputLength = strlen(source);
161 int encodeLength = QRspec_getDataLength(sQRCodeVersion, sQRCodeLevel) - 3;
162 while (inputLength > 0) {
163 int copyCount = 0;
164 if (sWebPostId[0] != 0) {
165 copyCount = encode_url(sWebPostCounter++ == 0 ? "clear" : "d",
166 source, encodeLength, inputLength);
167 if (copyCount < 0) {
168 kprintf("Failed to URL encode buffer.\n");
169 QRcode_clearCache();
170 return 1;
172 } else {
173 copyCount = inputLength < encodeLength ? inputLength : encodeLength;
174 memcpy(sEncodeBuffer, source, copyCount);
175 sEncodeBuffer[copyCount] = 0;
178 QRcode* qrCode = QRcode_encodeString8bit(sEncodeBuffer, sQRCodeVersion,
179 sQRCodeLevel);
180 if (qrCode == NULL) {
181 kprintf("Failed to encode buffer into qr code.\n");
182 QRcode_clearCache();
183 return 1;
186 source += copyCount;
187 inputLength -= copyCount;
189 bool doContinue = print_qrcode(qrCode, inputLength > 0);
190 QRcode_free(qrCode);
192 if (!doContinue) {
193 QRcode_clearCache();
194 abort_debugger_command();
195 // Does not return.
199 QRcode_clearCache();
200 return 0;
204 static int
205 qrclear(int argc, char* argv[])
207 if (argc > 1 && strcmp(argv[1], "--help") == 0) {
208 kprintf("Clears the current QR buffer.\n");
209 return 0;
212 sBufferPosition = 0;
213 sStringBuffer[0] = 0;
214 return 0;
218 static int
219 qrflush(int argc, char* argv[])
221 if (argc > 1 && strcmp(argv[1], "--help") == 0) {
222 kprintf("Flushes the current QR buffer by encoding QR codes from\n"
223 "the data and then clears the QR buffer.\n");
224 return 1;
227 qrencode(0, NULL);
228 qrclear(0, NULL);
229 return 0;
233 static int
234 qrappend(int argc, char* argv[])
236 if (argc < 2 || (argc > 1 && strcmp(argv[1], "--help") == 0)) {
237 kprintf("%s <string>\n", argv[0]);
238 kprintf("Appends the given string to the QR buffer. Can be used as\n"
239 "the target of a pipe command to accumulate the output of other\n"
240 "commands in the QR buffer.\n"
241 "Note that this command will flush the QR buffer when it runs\n"
242 "full to make room for the new string. This will cause QR codes\n"
243 "to be generated while the append command still runs. As these\n"
244 "implicit flushes only happen to make room in the buffer, the\n"
245 "strings are afterwards appended aren't flushed, so make sure to\n"
246 "execute the qrflush command to generate codes for these as\n"
247 "well.\n");
248 return 1;
251 const char* source = argv[1];
252 int length = strlen(source) + 1;
254 while (length > 0) {
255 int copyCount = sizeof(sStringBuffer) - sBufferPosition - 1;
256 if (copyCount == 0) {
257 // The buffer is full, we need to flush it.
258 qrflush(0, NULL);
261 if (length < copyCount)
262 copyCount = length;
264 memcpy(sStringBuffer + sBufferPosition, source, copyCount);
265 sBufferPosition += copyCount;
266 source += copyCount;
267 length -= copyCount;
270 // Overwrite the 0 byte that was copied extra with a newline.
271 if (sBufferPosition > 0)
272 sStringBuffer[sBufferPosition - 1] = '\n';
274 return 0;
278 static int
279 qrconfig(int argc, char* argv[])
281 if (argc < 2 || (argc > 1 && strcmp(argv[1], "--help") == 0)) {
282 kprintf("%s <version>\n", argv[0]);
283 kprintf("Sets the QR version to be used. Valid versions range from 1\n"
284 "to 40 where each version determines the size of the QR code.\n"
285 "Version 1 is 21x21 in size and each version increments that size\n"
286 "by 4x4 up to 177x177 for version 40.\n"
287 "Bigger QR codes can hold more data, so ideally you use a version\n"
288 "that makes the QR code as big as possible while still fitting on\n"
289 "your screen.\n"
290 "You can test the new config by running qrencode\n"
291 "with a test string.\n"
292 "Note that due to memory constraints in the kernel debugger, some\n"
293 "of the higher versions may actually not work. The kernel\n"
294 "debugger heap size can be adjusted using the KDEBUG_HEAP define\n"
295 "in the kernel_debug_config.h header\n");
296 return 1;
299 int newVersion = atoi(argv[1]);
300 if (newVersion <= 0 || newVersion > 40) {
301 kprintf("Invalid QR code version supplied, "
302 "must be between 1 and 40.\n");
303 return 1;
306 sQRCodeVersion = newVersion;
307 return 0;
311 static int
312 qrwebpost(int argc, char* argv[])
314 if (argc >= 3 && strcmp(argv[1], "start") == 0) {
315 strlcpy(sWebPostId, argv[2], sizeof(sWebPostId));
316 sWebPostCounter = 0;
318 // Generate the clear code.
319 const char* args[2] = { "", "yes" };
320 qrencode(2, (char**)args);
321 } else if (argc >= 2 && strcmp(argv[1], "stop") == 0) {
322 sWebPostId[0] = 0;
323 } else {
324 kprintf("%s start <id>\n", argv[0]);
325 kprintf("%s stop\n", argv[0]);
326 kprintf("Causes the QR codes to be rendered as URLs that resolve to\n"
327 "a service that allows appending the data of multiple QR codes\n"
328 "for easier handling.\n"
329 "An initial QR code is generated that invokes a clear operation\n"
330 "to prepare the output file on the server.\n"
331 "Note that there is no logic behind the service, if you and\n"
332 "someone else use the same id at the same time, they will\n"
333 "overwrite eachother. Therefore use a reasonably unique name.\n");
334 return 1;
337 return 0;
341 static status_t
342 std_ops(int32 op, ...)
344 switch (op) {
345 case B_MODULE_INIT:
346 add_debugger_command("qrencode", qrencode,
347 "encodes a string / the current QR buffer");
348 add_debugger_command("qrappend", qrappend,
349 "appends a string to the QR buffer");
350 add_debugger_command("qrclear", qrclear,
351 "clears the current QR buffer");
352 add_debugger_command("qrflush", qrflush,
353 "encodes the current QR buffer and clears it");
354 add_debugger_command("qrconfig", qrconfig,
355 "sets the QR code version to be used");
356 add_debugger_command("qrwebpost", qrwebpost,
357 "sets up URL encoding for QR codes");
358 return B_OK;
359 case B_MODULE_UNINIT:
360 remove_debugger_command("qrencode", qrencode);
361 remove_debugger_command("qrappend", qrappend);
362 remove_debugger_command("qrclear", qrclear);
363 remove_debugger_command("qrflush", qrflush);
364 remove_debugger_command("qrconfig", qrconfig);
365 remove_debugger_command("qrwebpost", qrwebpost);
366 return B_OK;
369 return B_BAD_VALUE;
373 static struct debugger_module_info sModuleInfo = {
375 "debugger/qrencode/v1",
377 &std_ops
379 NULL,
380 NULL,
381 NULL,
382 NULL
385 module_info *modules[] = {
386 (module_info *)&sModuleInfo,
387 NULL