xref: /haiku/src/add-ons/kernel/debugger/qrencode/module.cpp (revision 25a7b01d15612846f332751841da3579db313082)
10948c0ffSMichael Lotz /*
20948c0ffSMichael Lotz  * Copyright 2012, Haiku, Inc. All rights reserved.
30948c0ffSMichael Lotz  * Distributed under the terms of the MIT License.
40948c0ffSMichael Lotz  *
50948c0ffSMichael Lotz  * Authors:
60948c0ffSMichael Lotz  *		Michael Lotz <mmlr@mlotz.ch>
70948c0ffSMichael Lotz  */
80948c0ffSMichael Lotz 
90948c0ffSMichael Lotz 
100948c0ffSMichael Lotz #include <debug.h>
11a86c7d0aSMichael Lotz #include <stdio.h>
120948c0ffSMichael Lotz #include <stdlib.h>
130948c0ffSMichael Lotz #include <string.h>
140948c0ffSMichael Lotz 
150948c0ffSMichael Lotz extern "C" {
160948c0ffSMichael Lotz #include "qrencode.h"
170948c0ffSMichael Lotz #include "qrspec.h"
180948c0ffSMichael Lotz }
190948c0ffSMichael Lotz 
200948c0ffSMichael Lotz 
21e0ef5b2aSMichael Lotz extern "C" {
22e0ef5b2aSMichael Lotz extern void abort_debugger_command();
23e0ef5b2aSMichael Lotz }
24e0ef5b2aSMichael Lotz 
25e0ef5b2aSMichael Lotz 
262a80abaaSMichael Lotz static const char* kWebPostBaseURL = "http://mlotz.ch/q";
27a86c7d0aSMichael Lotz 
280948c0ffSMichael Lotz static char sStringBuffer[16 * 1024];
290948c0ffSMichael Lotz static char sEncodeBuffer[3 * 1024];
300948c0ffSMichael Lotz static int sBufferPosition = 0;
310948c0ffSMichael Lotz static int sQRCodeVersion = 19;
320948c0ffSMichael Lotz static QRecLevel sQRCodeLevel = QR_ECLEVEL_L;
33a86c7d0aSMichael Lotz static char sWebPostId[64];
34a86c7d0aSMichael Lotz static int sWebPostCounter = 0;
350948c0ffSMichael Lotz 
360948c0ffSMichael Lotz 
370948c0ffSMichael Lotz static bool
qrcode_bit(QRcode * qrCode,int x,int y)380948c0ffSMichael Lotz qrcode_bit(QRcode* qrCode, int x, int y)
390948c0ffSMichael Lotz {
400948c0ffSMichael Lotz 	if (x >= qrCode->width || y >= qrCode->width)
410948c0ffSMichael Lotz 		return false;
420948c0ffSMichael Lotz 
430948c0ffSMichael Lotz 	return (qrCode->data[y * qrCode->width + x] & 0x01) == 1;
440948c0ffSMichael Lotz }
450948c0ffSMichael Lotz 
460948c0ffSMichael Lotz 
470948c0ffSMichael Lotz static void
move_to_and_clear_line(int line)480948c0ffSMichael Lotz move_to_and_clear_line(int line)
490948c0ffSMichael Lotz {
500948c0ffSMichael Lotz 	kprintf(" \x1b[%dd\x1b[G\x1b[K", line + 1);
510948c0ffSMichael Lotz }
520948c0ffSMichael Lotz 
530948c0ffSMichael Lotz 
5439a26a0aSMichael Lotz static bool
print_qrcode(QRcode * qrCode,bool waitForKey)550948c0ffSMichael Lotz print_qrcode(QRcode* qrCode, bool waitForKey)
560948c0ffSMichael Lotz {
570948c0ffSMichael Lotz 	move_to_and_clear_line(0);
580948c0ffSMichael Lotz 	for (int y = 0; y < qrCode->width; y += 2) {
590948c0ffSMichael Lotz 		move_to_and_clear_line(y / 2 + 1);
600948c0ffSMichael Lotz 		kputs("  ");
610948c0ffSMichael Lotz 
620948c0ffSMichael Lotz 		for (int x = 0; x < qrCode->width; x++) {
630948c0ffSMichael Lotz 			bool upper = qrcode_bit(qrCode, x, y);
640948c0ffSMichael Lotz 			bool lower = qrcode_bit(qrCode, x, y + 1);
650948c0ffSMichael Lotz 			if (upper == lower)
660948c0ffSMichael Lotz 				kputs(upper ? "\x11" : " ");
670948c0ffSMichael Lotz 			else
680948c0ffSMichael Lotz 				kputs(upper ? "\x12" : "\x13");
690948c0ffSMichael Lotz 		}
700948c0ffSMichael Lotz 	}
710948c0ffSMichael Lotz 
720948c0ffSMichael Lotz 	move_to_and_clear_line(qrCode->width / 2 + 2);
730948c0ffSMichael Lotz 	move_to_and_clear_line(qrCode->width / 2 + 3);
740948c0ffSMichael Lotz 
750948c0ffSMichael Lotz 	if (waitForKey) {
76e0ef5b2aSMichael Lotz 		kputs("press q to abort or any other key to continue...\x1b[1B\x1b[G");
77e0ef5b2aSMichael Lotz 		if (kgetc() == 'q')
7839a26a0aSMichael Lotz 			return false;
790948c0ffSMichael Lotz 	}
8039a26a0aSMichael Lotz 
8139a26a0aSMichael Lotz 	return true;
820948c0ffSMichael Lotz }
830948c0ffSMichael Lotz 
840948c0ffSMichael Lotz 
850948c0ffSMichael Lotz static int
encode_url(const char * query,const char * data,int encodeLength,int inputLength)86a86c7d0aSMichael Lotz encode_url(const char* query, const char* data, int encodeLength,
87a86c7d0aSMichael Lotz 	int inputLength)
88a86c7d0aSMichael Lotz {
89a86c7d0aSMichael Lotz 	sEncodeBuffer[0] = 0;
90a86c7d0aSMichael Lotz 	strlcat(sEncodeBuffer, kWebPostBaseURL, encodeLength + 1);
912a80abaaSMichael Lotz 	strlcat(sEncodeBuffer, "?i=", encodeLength + 1);
92a86c7d0aSMichael Lotz 	strlcat(sEncodeBuffer, sWebPostId, encodeLength + 1);
93a86c7d0aSMichael Lotz 	strlcat(sEncodeBuffer, "&", encodeLength + 1);
94a86c7d0aSMichael Lotz 	strlcat(sEncodeBuffer, query, encodeLength + 1);
95a86c7d0aSMichael Lotz 	int position = strlcat(sEncodeBuffer, "=", encodeLength + 1);
96a86c7d0aSMichael Lotz 	if (position > encodeLength)
97a86c7d0aSMichael Lotz 		return -1;
98a86c7d0aSMichael Lotz 
99a86c7d0aSMichael Lotz 	int copyCount = 0;
100a86c7d0aSMichael Lotz 	while (inputLength > 0 && position < encodeLength) {
101a86c7d0aSMichael Lotz 		char character = data[copyCount];
102a86c7d0aSMichael Lotz 		if ((character >= 'a' && character <= 'z')
103a86c7d0aSMichael Lotz 			|| (character >= 'A' && character <= 'Z')
104a86c7d0aSMichael Lotz 			|| (character >= '0' && character <= '9')
105a86c7d0aSMichael Lotz 			|| character == '.' || character == '-' || character == '_'
106*5dc5dbbbSMichael Lotz 			|| character == '~'
107*5dc5dbbbSMichael Lotz 			// These aren't strictly valid, but seem to work.
108*5dc5dbbbSMichael Lotz 			|| character == '/' || character == '(' || character == ')'
109*5dc5dbbbSMichael Lotz 			|| character == '=' || character == '^' || character == '?'
110*5dc5dbbbSMichael Lotz 			|| character == '|' || character == '*' || character == '@'
111*5dc5dbbbSMichael Lotz 			|| character == ';' || character == ':' || character == ','
112*5dc5dbbbSMichael Lotz 			|| character == '{' || character == '}' || character == '['
113*5dc5dbbbSMichael Lotz 			|| character == ']' || character == '<' || character == '>'
114*5dc5dbbbSMichael Lotz 			|| character == '!' || character == '\\') {
115a86c7d0aSMichael Lotz 			sEncodeBuffer[position++] = character;
116a86c7d0aSMichael Lotz 			sEncodeBuffer[position] = 0;
117*5dc5dbbbSMichael Lotz 		} else if (character == ' ') {
118*5dc5dbbbSMichael Lotz 			// Encode spaces as '+' as that's shorter than %20.
119*5dc5dbbbSMichael Lotz 			sEncodeBuffer[position++] = '+';
120*5dc5dbbbSMichael Lotz 			sEncodeBuffer[position] = 0;
121a86c7d0aSMichael Lotz 		} else {
122a86c7d0aSMichael Lotz 			// Encode to a %xx escape.
123a86c7d0aSMichael Lotz 			if (encodeLength - position < 3) {
124a86c7d0aSMichael Lotz 				// Doesn't fit anymore, we're done.
125a86c7d0aSMichael Lotz 				break;
126a86c7d0aSMichael Lotz 			}
127a86c7d0aSMichael Lotz 
128a86c7d0aSMichael Lotz 			char escaped[4];
129a86c7d0aSMichael Lotz 			sprintf(escaped, "%%%.2x", character);
130a86c7d0aSMichael Lotz 			position = strlcat(sEncodeBuffer, escaped, encodeLength + 1);
131a86c7d0aSMichael Lotz 		}
132a86c7d0aSMichael Lotz 
133a86c7d0aSMichael Lotz 		inputLength--;
134a86c7d0aSMichael Lotz 		copyCount++;
135a86c7d0aSMichael Lotz 	}
136a86c7d0aSMichael Lotz 
137a86c7d0aSMichael Lotz 	return copyCount;
138a86c7d0aSMichael Lotz }
139a86c7d0aSMichael Lotz 
140a86c7d0aSMichael Lotz 
141a86c7d0aSMichael Lotz static int
qrencode(int argc,char * argv[])1420948c0ffSMichael Lotz qrencode(int argc, char* argv[])
1430948c0ffSMichael Lotz {
1440948c0ffSMichael Lotz 	if (argc > 1 && strcmp(argv[1], "--help") == 0) {
1450948c0ffSMichael Lotz 		kprintf("%s [<string>]\n", argv[0]);
1460948c0ffSMichael Lotz 		kprintf("If an argument is given, encodes that string as a QR code.\n"
1470948c0ffSMichael Lotz 			"Otherwise the current QR buffer is encoded as QR codes.\n"
1480948c0ffSMichael Lotz 			"When encoding from the QR buffer, the buffer is left intact.\n"
1490948c0ffSMichael Lotz 			"use qrclear to clear the QR buffer or qrflush to encode/clear.\n");
1500948c0ffSMichael Lotz 		return 1;
1510948c0ffSMichael Lotz 	}
1520948c0ffSMichael Lotz 
1530948c0ffSMichael Lotz 	const char* source = NULL;
1540948c0ffSMichael Lotz 	if (argc < 2) {
1550948c0ffSMichael Lotz 		sStringBuffer[sBufferPosition] = 0;
1560948c0ffSMichael Lotz 		source = sStringBuffer;
1570948c0ffSMichael Lotz 	} else
1580948c0ffSMichael Lotz 		source = argv[1];
1590948c0ffSMichael Lotz 
1600948c0ffSMichael Lotz 	int inputLength = strlen(source);
1610948c0ffSMichael Lotz 	int encodeLength = QRspec_getDataLength(sQRCodeVersion, sQRCodeLevel) - 3;
1620948c0ffSMichael Lotz 	while (inputLength > 0) {
163a86c7d0aSMichael Lotz 		int copyCount = 0;
164a86c7d0aSMichael Lotz 		if (sWebPostId[0] != 0) {
1652a80abaaSMichael Lotz 			copyCount = encode_url(sWebPostCounter++ == 0 ? "clear" : "d",
166a86c7d0aSMichael Lotz 				source, encodeLength, inputLength);
167a86c7d0aSMichael Lotz 			if (copyCount < 0) {
168a86c7d0aSMichael Lotz 				kprintf("Failed to URL encode buffer.\n");
169a86c7d0aSMichael Lotz 				QRcode_clearCache();
170a86c7d0aSMichael Lotz 				return 1;
171a86c7d0aSMichael Lotz 			}
172a86c7d0aSMichael Lotz 		} else {
173a86c7d0aSMichael Lotz 			copyCount = inputLength < encodeLength ? inputLength : encodeLength;
1740948c0ffSMichael Lotz 			memcpy(sEncodeBuffer, source, copyCount);
1750948c0ffSMichael Lotz 			sEncodeBuffer[copyCount] = 0;
176a86c7d0aSMichael Lotz 		}
1770948c0ffSMichael Lotz 
1780948c0ffSMichael Lotz 		QRcode* qrCode = QRcode_encodeString8bit(sEncodeBuffer, sQRCodeVersion,
1790948c0ffSMichael Lotz 			sQRCodeLevel);
1800948c0ffSMichael Lotz 		if (qrCode == NULL) {
181a86c7d0aSMichael Lotz 			kprintf("Failed to encode buffer into qr code.\n");
1820948c0ffSMichael Lotz 			QRcode_clearCache();
1830948c0ffSMichael Lotz 			return 1;
1840948c0ffSMichael Lotz 		}
1850948c0ffSMichael Lotz 
1860948c0ffSMichael Lotz 		source += copyCount;
1870948c0ffSMichael Lotz 		inputLength -= copyCount;
1880948c0ffSMichael Lotz 
18939a26a0aSMichael Lotz 		bool doContinue = print_qrcode(qrCode, inputLength > 0);
1900948c0ffSMichael Lotz 		QRcode_free(qrCode);
19139a26a0aSMichael Lotz 
19239a26a0aSMichael Lotz 		if (!doContinue) {
19339a26a0aSMichael Lotz 			QRcode_clearCache();
19439a26a0aSMichael Lotz 			abort_debugger_command();
19539a26a0aSMichael Lotz 				// Does not return.
19639a26a0aSMichael Lotz 		}
1970948c0ffSMichael Lotz 	}
1980948c0ffSMichael Lotz 
1990948c0ffSMichael Lotz 	QRcode_clearCache();
2000948c0ffSMichael Lotz 	return 0;
2010948c0ffSMichael Lotz }
2020948c0ffSMichael Lotz 
2030948c0ffSMichael Lotz 
2040948c0ffSMichael Lotz static int
qrclear(int argc,char * argv[])2050948c0ffSMichael Lotz qrclear(int argc, char* argv[])
2060948c0ffSMichael Lotz {
2070948c0ffSMichael Lotz 	if (argc > 1 && strcmp(argv[1], "--help") == 0) {
2080948c0ffSMichael Lotz 		kprintf("Clears the current QR buffer.\n");
2090948c0ffSMichael Lotz 		return 0;
2100948c0ffSMichael Lotz 	}
2110948c0ffSMichael Lotz 
2120948c0ffSMichael Lotz 	sBufferPosition = 0;
2130948c0ffSMichael Lotz 	sStringBuffer[0] = 0;
2140948c0ffSMichael Lotz 	return 0;
2150948c0ffSMichael Lotz }
2160948c0ffSMichael Lotz 
2170948c0ffSMichael Lotz 
2180948c0ffSMichael Lotz static int
qrflush(int argc,char * argv[])2190948c0ffSMichael Lotz qrflush(int argc, char* argv[])
2200948c0ffSMichael Lotz {
2210948c0ffSMichael Lotz 	if (argc > 1 && strcmp(argv[1], "--help") == 0) {
2220948c0ffSMichael Lotz 		kprintf("Flushes the current QR buffer by encoding QR codes from\n"
2230948c0ffSMichael Lotz 			"the data and then clears the QR buffer.\n");
2240948c0ffSMichael Lotz 		return 1;
2250948c0ffSMichael Lotz 	}
2260948c0ffSMichael Lotz 
2270948c0ffSMichael Lotz 	qrencode(0, NULL);
2280948c0ffSMichael Lotz 	qrclear(0, NULL);
2290948c0ffSMichael Lotz 	return 0;
2300948c0ffSMichael Lotz }
2310948c0ffSMichael Lotz 
2320948c0ffSMichael Lotz 
2330948c0ffSMichael Lotz static int
qrappend(int argc,char * argv[])2340948c0ffSMichael Lotz qrappend(int argc, char* argv[])
2350948c0ffSMichael Lotz {
2360948c0ffSMichael Lotz 	if (argc < 2 || (argc > 1 && strcmp(argv[1], "--help") == 0)) {
2370948c0ffSMichael Lotz 		kprintf("%s <string>\n", argv[0]);
2380948c0ffSMichael Lotz 		kprintf("Appends the given string to the QR buffer. Can be used as\n"
2390948c0ffSMichael Lotz 			"the target of a pipe command to accumulate the output of other\n"
2400948c0ffSMichael Lotz 			"commands in the QR buffer.\n"
2410948c0ffSMichael Lotz 			"Note that this command will flush the QR buffer when it runs\n"
2420948c0ffSMichael Lotz 			"full to make room for the new string. This will cause QR codes\n"
2430948c0ffSMichael Lotz 			"to be generated while the append command still runs. As these\n"
2440948c0ffSMichael Lotz 			"implicit flushes only happen to make room in the buffer, the\n"
2450948c0ffSMichael Lotz 			"strings are afterwards appended aren't flushed, so make sure to\n"
2460948c0ffSMichael Lotz 			"execute the qrflush command to generate codes for these as\n"
2470948c0ffSMichael Lotz 			"well.\n");
2480948c0ffSMichael Lotz 		return 1;
2490948c0ffSMichael Lotz 	}
2500948c0ffSMichael Lotz 
2510948c0ffSMichael Lotz 	const char* source = argv[1];
2520948c0ffSMichael Lotz 	int length = strlen(source) + 1;
2530948c0ffSMichael Lotz 
2540948c0ffSMichael Lotz 	while (length > 0) {
2550948c0ffSMichael Lotz 		int copyCount = sizeof(sStringBuffer) - sBufferPosition - 1;
2560948c0ffSMichael Lotz 		if (copyCount == 0) {
2570948c0ffSMichael Lotz 			// The buffer is full, we need to flush it.
2580948c0ffSMichael Lotz 			qrflush(0, NULL);
2590948c0ffSMichael Lotz 		}
2600948c0ffSMichael Lotz 
2610948c0ffSMichael Lotz 		if (length < copyCount)
2620948c0ffSMichael Lotz 			copyCount = length;
2630948c0ffSMichael Lotz 
2640948c0ffSMichael Lotz 		memcpy(sStringBuffer + sBufferPosition, source, copyCount);
2650948c0ffSMichael Lotz 		sBufferPosition += copyCount;
2660948c0ffSMichael Lotz 		source += copyCount;
2670948c0ffSMichael Lotz 		length -= copyCount;
2680948c0ffSMichael Lotz 	}
2690948c0ffSMichael Lotz 
2700948c0ffSMichael Lotz 	// Overwrite the 0 byte that was copied extra with a newline.
2710948c0ffSMichael Lotz 	if (sBufferPosition > 0)
2720948c0ffSMichael Lotz 		sStringBuffer[sBufferPosition - 1] = '\n';
2730948c0ffSMichael Lotz 
2740948c0ffSMichael Lotz 	return 0;
2750948c0ffSMichael Lotz }
2760948c0ffSMichael Lotz 
2770948c0ffSMichael Lotz 
2780948c0ffSMichael Lotz static int
qrconfig(int argc,char * argv[])2790948c0ffSMichael Lotz qrconfig(int argc, char* argv[])
2800948c0ffSMichael Lotz {
2810948c0ffSMichael Lotz 	if (argc < 2 || (argc > 1 && strcmp(argv[1], "--help") == 0)) {
2820948c0ffSMichael Lotz 		kprintf("%s <version>\n", argv[0]);
2830948c0ffSMichael Lotz 		kprintf("Sets the QR version to be used. Valid versions range from 1\n"
2840948c0ffSMichael Lotz 			"to 40 where each version determines the size of the QR code.\n"
2850948c0ffSMichael Lotz 			"Version 1 is 21x21 in size and each version increments that size\n"
2860948c0ffSMichael Lotz 			"by 4x4 up to 177x177 for version 40.\n"
2870948c0ffSMichael Lotz 			"Bigger QR codes can hold more data, so ideally you use a version\n"
2880948c0ffSMichael Lotz 			"that makes the QR code as big as possible while still fitting on\n"
2890948c0ffSMichael Lotz 			"your screen.\n"
2900948c0ffSMichael Lotz 			"You can test the new config by running qrencode\n"
2910948c0ffSMichael Lotz 			"with a test string.\n"
2920948c0ffSMichael Lotz 			"Note that due to memory constraints in the kernel debugger, some\n"
2930948c0ffSMichael Lotz 			"of the higher versions may actually not work. The kernel\n"
2940948c0ffSMichael Lotz 			"debugger heap size can be adjusted using the KDEBUG_HEAP define\n"
2950948c0ffSMichael Lotz 			"in the kernel_debug_config.h header\n");
2960948c0ffSMichael Lotz 		return 1;
2970948c0ffSMichael Lotz 	}
2980948c0ffSMichael Lotz 
2990948c0ffSMichael Lotz 	int newVersion = atoi(argv[1]);
3000948c0ffSMichael Lotz 	if (newVersion <= 0 || newVersion > 40) {
3010948c0ffSMichael Lotz 		kprintf("Invalid QR code version supplied, "
3020948c0ffSMichael Lotz 			"must be between 1 and 40.\n");
3030948c0ffSMichael Lotz 		return 1;
3040948c0ffSMichael Lotz 	}
3050948c0ffSMichael Lotz 
3060948c0ffSMichael Lotz 	sQRCodeVersion = newVersion;
3070948c0ffSMichael Lotz 	return 0;
3080948c0ffSMichael Lotz }
3090948c0ffSMichael Lotz 
3100948c0ffSMichael Lotz 
311a86c7d0aSMichael Lotz static int
qrwebpost(int argc,char * argv[])312a86c7d0aSMichael Lotz qrwebpost(int argc, char* argv[])
313a86c7d0aSMichael Lotz {
314a86c7d0aSMichael Lotz 	if (argc >= 3 && strcmp(argv[1], "start") == 0) {
315a86c7d0aSMichael Lotz 		strlcpy(sWebPostId, argv[2], sizeof(sWebPostId));
316a86c7d0aSMichael Lotz 		sWebPostCounter = 0;
317a86c7d0aSMichael Lotz 
318a86c7d0aSMichael Lotz 		// Generate the clear code.
319a86c7d0aSMichael Lotz 		const char* args[2] = { "", "yes" };
320a86c7d0aSMichael Lotz 		qrencode(2, (char**)args);
321a86c7d0aSMichael Lotz 	} else if (argc >= 2 && strcmp(argv[1], "stop") == 0) {
322a86c7d0aSMichael Lotz 		sWebPostId[0] = 0;
323a86c7d0aSMichael Lotz 	} else {
324a86c7d0aSMichael Lotz 		kprintf("%s start <id>\n", argv[0]);
325a86c7d0aSMichael Lotz 		kprintf("%s stop\n", argv[0]);
326a86c7d0aSMichael Lotz 		kprintf("Causes the QR codes to be rendered as URLs that resolve to\n"
327a86c7d0aSMichael Lotz 			"a service that allows appending the data of multiple QR codes\n"
328a86c7d0aSMichael Lotz 			"for easier handling.\n"
329a86c7d0aSMichael Lotz 			"An initial QR code is generated that invokes a clear operation\n"
330a86c7d0aSMichael Lotz 			"to prepare the output file on the server.\n"
331a86c7d0aSMichael Lotz 			"Note that there is no logic behind the service, if you and\n"
332a86c7d0aSMichael Lotz 			"someone else use the same id at the same time, they will\n"
333a86c7d0aSMichael Lotz 			"overwrite eachother. Therefore use a reasonably unique name.\n");
334a86c7d0aSMichael Lotz 		return 1;
335a86c7d0aSMichael Lotz 	}
336a86c7d0aSMichael Lotz 
337a86c7d0aSMichael Lotz 	return 0;
338a86c7d0aSMichael Lotz }
339a86c7d0aSMichael Lotz 
340a86c7d0aSMichael Lotz 
3410948c0ffSMichael Lotz static status_t
std_ops(int32 op,...)3420948c0ffSMichael Lotz std_ops(int32 op, ...)
3430948c0ffSMichael Lotz {
3440948c0ffSMichael Lotz 	switch (op) {
3450948c0ffSMichael Lotz 		case B_MODULE_INIT:
3460948c0ffSMichael Lotz 			add_debugger_command("qrencode", qrencode,
3470948c0ffSMichael Lotz 				"encodes a string / the current QR buffer");
3480948c0ffSMichael Lotz 			add_debugger_command("qrappend", qrappend,
3490948c0ffSMichael Lotz 				"appends a string to the QR buffer");
3500948c0ffSMichael Lotz 			add_debugger_command("qrclear", qrclear,
3510948c0ffSMichael Lotz 				"clears the current QR buffer");
3520948c0ffSMichael Lotz 			add_debugger_command("qrflush", qrflush,
3530948c0ffSMichael Lotz 				"encodes the current QR buffer and clears it");
3540948c0ffSMichael Lotz 			add_debugger_command("qrconfig", qrconfig,
3550948c0ffSMichael Lotz 				"sets the QR code version to be used");
356a86c7d0aSMichael Lotz 			add_debugger_command("qrwebpost", qrwebpost,
357a86c7d0aSMichael Lotz 				"sets up URL encoding for QR codes");
3580948c0ffSMichael Lotz 			return B_OK;
3590948c0ffSMichael Lotz 		case B_MODULE_UNINIT:
3600948c0ffSMichael Lotz 			remove_debugger_command("qrencode", qrencode);
3610948c0ffSMichael Lotz 			remove_debugger_command("qrappend", qrappend);
3620948c0ffSMichael Lotz 			remove_debugger_command("qrclear", qrclear);
3630948c0ffSMichael Lotz 			remove_debugger_command("qrflush", qrflush);
3640948c0ffSMichael Lotz 			remove_debugger_command("qrconfig", qrconfig);
365a86c7d0aSMichael Lotz 			remove_debugger_command("qrwebpost", qrwebpost);
3660948c0ffSMichael Lotz 			return B_OK;
3670948c0ffSMichael Lotz 	}
3680948c0ffSMichael Lotz 
3690948c0ffSMichael Lotz 	return B_BAD_VALUE;
3700948c0ffSMichael Lotz }
3710948c0ffSMichael Lotz 
3720948c0ffSMichael Lotz 
3730948c0ffSMichael Lotz static struct debugger_module_info sModuleInfo = {
3740948c0ffSMichael Lotz 	{
3750948c0ffSMichael Lotz 		"debugger/qrencode/v1",
3760948c0ffSMichael Lotz 		0,
3770948c0ffSMichael Lotz 		&std_ops
3780948c0ffSMichael Lotz 	},
3790948c0ffSMichael Lotz 	NULL,
3800948c0ffSMichael Lotz 	NULL,
3810948c0ffSMichael Lotz 	NULL,
3820948c0ffSMichael Lotz 	NULL
3830948c0ffSMichael Lotz };
3840948c0ffSMichael Lotz 
3850948c0ffSMichael Lotz module_info *modules[] = {
3860948c0ffSMichael Lotz 	(module_info *)&sModuleInfo,
3870948c0ffSMichael Lotz 	NULL
3880948c0ffSMichael Lotz };
3890948c0ffSMichael Lotz 
390