bug#2947: 23.0.91; font-lock-mode will hang emacs on this file (both on Windows/Linux)

Bao Haojun <[email protected]>
Newsgroups gmane.emacs.bugs,gmane.emacs.pretest.bugs
Message-ID <[email protected]>
The file is attached, the offending character is the last `"' character on line 117:

	{"get micco", MICCO_TEST, "B<B>B>", "0x1", "},

If I run M-x font-lock-mode, emacs will hang. I have also tested on Linux emacs.


In GNU Emacs 23.0.91.1 (i386-mingw-nt5.1.2600)
 of 2009-02-27 on SOFT-MJASON
Windowing system distributor `Microsoft Corp.', version 5.1.2600
configured using `configure --with-gcc (3.4)'

Important settings:
  value of $LC_ALL: nil
  value of $LC_COLLATE: nil
  value of $LC_CTYPE: nil
  value of $LC_MESSAGES: nil
  value of $LC_MONETARY: nil
  value of $LC_NUMERIC: nil
  value of $LC_TIME: nil
  value of $LANG: CHS
  value of $XMODIFIERS: nil
  locale-coding-system: cp936
  default-enable-multibyte-characters: t

Major mode: C++/l

Minor modes in effect:
  auto-image-file-mode: t
  shell-dirtrack-mode: t
  mouse-wheel-mode: t
  file-name-shadow-mode: t
  blink-cursor-mode: t
  global-auto-composition-mode: t
  auto-composition-mode: t
  auto-encryption-mode: t
  auto-compression-mode: t
  line-number-mode: t
  transient-mark-mode: t
  abbrev-mode: t

Recent input:
<help-echo> C-x C-f s r c / c l i <M-backspace> e n 
g <M-backspace> a l c <return> j s <return> <return> 
c l i <return> M-x M-p C-k f o n t <tab> l o <tab> 
m o <tab> <return> C-e C-b C-b " C-x C-s M-x C-g M-x 
g l o b <tab> f o n <tab> <return> M-x r e p o r <tab> 
<return>

Recent messages:
Loading paren...done
Loading q:/.session...done
For information about GNU Emacs and the GNU system, type C-h C-a.
Searching for `cli'....
Loading vc-svn...done
Font-Lock mode disabled
Saving file q:/src/alchemy/JSC-fork-dll/AlchemyLib/cli.cpp...
Wrote q:/src/alchemy/JSC-fork-dll/AlchemyLib/cli.cpp
Quit
Global-Font-Lock mode disabled

#include "stdafx.h"
#include "alchemy_internal.h"

#include <afxtempl.h>
#include "cli.h"
#define ENABLE_BHJDEBUG
#include "bhjdebug.h" 

typedef enum
{
    FACTORY_ID     = 0x001,
    GPIO_TEST      = 0x003,
    REGISTER_TEST = 0x004,
    ADC_TEST = 0x005,
    REBOOT_TEST = 0x006,
    CAMERA_TEST = 0x007,
    BLUETOOTH_TEST = 0x008,
    TESTINFO       = 0x009,
    ATPARSER_TEST  = 0x00a,
    VIBRATOR_TEST = 0x00b,
    POWERREASON_TEST=0x00c,
    VOLTAGE_TEST = 0x00d,  /*get real voltage by ADC */
    TEMPRATURE_TEST = 0x00e, /*get real temprature by ADC */
    CHARGETYPE_TEST =0x00f,
    GSENSOR_TEST   = 0x010,
    MICCO_TEST     = 0x011,
    LCDBACK_TEST   = 0x012,
    KEYBACK_TEST   = 0x013,
    TOUCH_POINT =0x014,
    KEY_INPUT = 0x015,
    ONLY_Key = 0x031,
    LGSENSOR_TEST  = 0x01c,
    GSENSOR_INFO   = 0x01d,
	
	/* DDR test commands */
    Ddr_TEST = 0x01f,
    /* LCD test commands */
    LCD_TEST = 0x20,
    /* T-FLASH card detect*/
    CARD_TEST =0x021,  

	/* charge status */
    CHARGESTATUS_TEST = 0x022, 
    
	/* MAT FILE Read AND write */
	MAT_TEST = 0x023 ,
	
       /*audio hardware test */
    AUDIO_TEST = 0x024,
     
    
/* ADC calibration &NVM block operation related test commands*/
    CALI_TEMP = 0x016, /*only operation on filesystem file*/
    CALI_VOLT = 0x017, /*only operation on filesystem file*/
    NVM_TEST  = 0X018,
    VOLT_TEST = 0x019, /*read /write from filesystem to NVM block*/
    TEMP_TEST = 0x01a, /*read /write from filesystem to NVM block*/
    RF_TEST   = 0x01b,  /*read /write from filesystem to NVM block*/
    TESTINFO_TEST =0x025,/*read /write from filesystem to NVM block*/
    FACTORYID_TEST=0x026,/*read /write from filesystem to NVM block*/
    MATFLAG_TEST=0x027,/*read /write from filesystem to NVM block*/
    
    /*touch panel test */
   PANEL_TEST = 0x028,
  /*empty  test */
   EMPTY_TEST = 0x029,
   
  /* bluetooth test commands */
    BT_TEST   = 0x050,
    BTNVM_TEST= 0x051,
    BT_INQUIRE= 0x052,
    BT_TESTMODE =0x053,
    BT_KILL=0x054,//kill the "/system/bin/hciattach" process after enter into BT Test Mode /BTINQUIRE 
   /*camera test commands */
    CAMERA_PREVIEW = 0x060,
    LAUNCH_CAMERA = 0x61,
    I2C_TEST  = 0x01e,
    
     /*CMMB test commands */
    IF101_TEST= 0x070,    
    INNO_DEVICE= 0x071, /*enter or exit CMMB test mode*/
    Signallock_TEST = 0x72,
    Sensitive_TEST = 0x73,
    IF101_SPI_TEST = 0x74,
    IF101_SET_FREQ = 0x75,
    LAUNCH_TV = 0x76,
   /* GPS test commands */ 
    GPS_TEST = 0x80,
    GPS_LOCATION=0x81,
    GPS_MESSAGE=0x82,/*only get NEMA Message*/
    GPS_LOCA_MESSAGE=0x83,/*only get Location Message*/
    GPS_CHANGE_MODE=0x84,/*Change between hot mode and code mode*/
  
    /* SPARK */
	SPARK_KEY=0x90,/*TEST KEY INPUT*/
	/* Key Monitor */
	KEY_MONITOR=0x91,
	/* Sensor Monitor */
	SENSOR_MONITOR=0x92,
	/* Set/Get LPR SMS report flag */
	SMS_FLAG =0x93,
	/* Set/Get LPR livetime period  */
    LIVETIME_PERIOD = 0x94,
    /* Set/Get EFEM feature flag  */
    EFEM_FLAG =0x95,
	DIAG_LAUNCH=0x96,	
	GET_RDNVM =0x9a,
	DIAG_EXT_INTERFACE=0x9b,
	/*to set /get element config value */
	NVM_Element=0x9c,
	/*to set /get phase  data : */
	NVM_PHASE =0x9d,
	/*Common set/get Bit config element value*/
	NVM_BITCONFIG  =0x9e, 
	/* Version */
	VERSION     = 0x039,
    
    /* bp only handler */
    BP_ONLY    = 0xFFFF
} TC_AP_FSM_EVENT_OPCODE_T;

typedef unsigned char u8;
typedef unsigned short u16;
typedef struct{
	const char *cmdName;
	int opCode;
	const char *inputSpec; // datatype: BHIOoF, how: <>*! 
	const char *fixedInput;
	const char *description;
	
} testCmd_T;


//< means from the fixedInput, 
//> means from user provided input, 
//! means arbitrary value is acceptable, so we just use 0, 
//* means fill with a string
static testCmd_T cmdMap[] = {
	{"version", VERSION, "B<", "0x12", "Read software version of the phone"},
	{"get factory_id", FACTORY_ID, "B<", "0x11", "Read FactoryId of the phone"},
	{"set factory_id", FACTORY_ID, "B<B*", "0x00", "Update FactoryId of the phone" },
	{"atCommand", ATPARSER_TEST, "B*", "", "Test an AT command" },
	{"get gpio", GPIO_TEST, "B<H>B!", "0x1", "Get GPIO, the u16 argument is the GPIO number"},

	{"set gpio", GPIO_TEST, "B<H>B>", "0x2", 
	 "Set GPIO, the u16 is GPIO number, the u8 is GPIO setting\n"
	 "the meaning of bit 7-0:\n"
	 "    level : 1,     //0:low,1:High\n"
	 "    in_out: 1,    //0:input, 1:output\n"
	 "    pullup: 1,    //0:no pullup,1:pullup\n"
	 "    pulldown:  1,    //0:no pulldown,1:pulldown\n"
	 "    tri_state: 1,    //0:anit_tristate,1:tristate\n"
	 "    reserved:  3;\n"
	},
	{"get register", REGISTER_TEST, "B<I>I!", "0x1", "Read register value, u32 is register number. Use with caution!"},
	{"set register", REGISTER_TEST, "B<I>I>", "0x2", "Write register, first u32 is register number, second is value"},
	{"get adc", ADC_TEST, "B>H!", "", "Read A/D converter value, u8 is AD number" },

	{"reboot poweroff", REBOOT_TEST, "B<", "0x0", "reboot to poweroff mode"},
	{"reboot factory", REBOOT_TEST, "B<", "0x1" "reboot to factory mode (minimal applications will start, so boot/test is faster)"},
	{"reboot normal", REBOOT_TEST, "B<", "0x2", "reboot, the `Normal' reboot"},
	{"reboot flash", REBOOT_TEST, "B<", "0x3", "reboot to flash mode"},

	//{"camera test", //???
	{"launch camera", LAUNCH_CAMERA, "", "", "lauch camera"},
	//{"bluetooth test", //???
	//{"get info", TESTINFO, "B<", "0x11"}, //???
	//{"set info", TESTINFO, "B<B*", "0x0"}, //???
	{"get gsensor", GSENSOR_TEST, "B<B>B!", "0x1", "get gravity sensor value, u8 is the gsensor number"},
	{"set gsensor", GSENSOR_TEST, "B<B>B>", "0x2", "set gsensor value, first u8 is the gsensor number, second is value"},
	{"get micco", MICCO_TEST, "B<B>B>", "0x1", "},
	{"set micco", MICCO_TEST, "B<B>B>", "0x2"},
	{"vibrator on", VIBRATOR_TEST, "B<", "0x1"},
	{"vibrator off", VIBRATOR_TEST, "B<", "0x2"},
	//{"at test" //bhj: don't know what this means
	{"get power reason", POWERREASON_TEST, "", ""},
	{"get chargetype", CHARGETYPE_TEST, "B<", "0x1"},
	{"set chargetype", CHARGETYPE_TEST, "B<B>", "0x2"},
	{"get manual voltage", VOLTAGE_TEST, "B<", "0x0"},
	{"get auto voltage", VOLTAGE_TEST, "B<", "0x4"},
	{"get manual temperature", TEMPRATURE_TEST, "B<", "0x1"},//0x0? 
	{"get auto temperature", TEMPRATURE_TEST, "B<", "0x5"},
	{"get lcdbl", LCDBACK_TEST, "B<B>", "0x1"},
	{"set lcdbl", LCDBACK_TEST, "B<B>", "0x2"},
	{"get keybl", KEYBACK_TEST, "B<B>", "0x1"},
	{"set keybl", KEYBACK_TEST, "B<B>", "0x2"},
	{"test touch", TOUCH_POINT, "", ""},
	{"test keyinput",ONLY_Key,"",""},
	{"get lprflag", SMS_FLAG, "B<", "0x1"},
	{"set lprflag", SMS_FLAG, "B<B>", "0x2"},
	{"get lprtime", LIVETIME_PERIOD, "B<", "0x1"},
	{"set lprtime", LIVETIME_PERIOD, "B<B>", "0x2"},
	{"get efemflag", EFEM_FLAG, "B<", "0x1"},
	{"set efemflag", EFEM_FLAG, "B<B>", "0x2"},
	{"get cali temperature",CALI_TEMP,"B<","0x1"},//add by Jason from here
	{"get cali voltage",CALI_VOLT,"B<","0x1"},
	{"set cali voltage",CALI_VOLT,"B<B*","0x2"},
	{"store volt",VOLT_TEST,"B<","0x1"},
	{"load volt",VOLT_TEST,"B<","0x2"},
	{"store temp",TEMP_TEST,"B<","0x1"},
	{"load temp",TEMP_TEST,"B<","0x2"},
	{"store RF",RF_TEST,"B<","0x1"},
	{"load RF",RF_TEST,"B<","0x2"},
	{"store testinfo",TESTINFO_TEST,"B<","0x1"},
	{"load testinfo",TESTINFO_TEST,"B<","0x2"},
	{"store factoryid",FACTORYID_TEST,"B<","0x1"},
	{"load factoryid",FACTORYID_TEST,"B<","0x2"},
	{"store MATflag",MATFLAG_TEST,"B<","0x1"},
	{"load MATflag",MATFLAG_TEST,"B<","0x2"},
	{"camera preview on",CAMERA_PREVIEW,"B<","0x1"},
	{"camera preview off",CAMERA_PREVIEW,"B<","0x2"},
	{"get sensor",LGSENSOR_TEST,"B<","0x1"},
	{"i2c test",I2C_TEST,"",""},
	{"if101 test",IF101_TEST,"",""},
	{"read bt",BT_TEST,"B<","0x1"},
	{"write bt",BT_TEST,"B<B*","0x2"},
	{"store btnvm",BTNVM_TEST,"B<B*","0x1"},
	{"load btnvm",BTNVM_TEST,"B<","0x2"},
	{"bt inquire",BT_INQUIRE,"",""},
	{"bt testmode",BT_TESTMODE,"",""},
	{"bt kill",BT_KILL,"",""},//ljs:not find the definition
	{"launch tv",LAUNCH_TV,"",""},
	{"ddr test",Ddr_TEST,"",""},
	{"gps test",GPS_TEST,"B>",""},
	{"lcd test",LCD_TEST,"B>",""},
	{"card detect",CARD_TEST,"B>",""},
	{"charge status",CHARGESTATUS_TEST,"B>",""},
	{"audio test",AUDIO_TEST,"B>",""},
	//data: 0x01: AUDIO_SD_PLAY
	//		0x02: AUDIO_MICRO_TEST
    //      0x03: AUDIO_EAR_TEST
	{"save rd",GET_RDNVM,"B<B>","0x1"},
	{"get diag_en",DIAG_LAUNCH,"B<","0x1"},
	{"set diag_en",DIAG_LAUNCH,"B<B>","0x2"},
	{"get diag_intf",DIAG_EXT_INTERFACE,"B<","0x1"},
	{"set diag_intf",DIAG_EXT_INTERFACE,"B<B>","0x2"},
	{"get element",NVM_Element,"I>B<","0x1"},
	{"set element",NVM_Element,"I>B<o","0x2"},
	{"get phase",NVM_PHASE,"I>B<","0x1"},
	{"set phase",NVM_PHASE,"I>B<o>","0x2"},
	{"get ap_panic_report",NVM_BITCONFIG,"I>B<","0x1"},
	{"set ap_panic_report",NVM_BITCONFIG,"I>B<B>","0x2"},
	{"opcode", -1, "o>", ""},
	{"reliable data", 0x97, "F>", ""},
	{NULL, 0, NULL, NULL},
};


static BOOL notOptionalCode(char c)
{
	return (c!='*' && c!='?');
}

static BOOL isOptionalCode(char c)
{
	return !notOptionalCode(c);
}

static BOOL isSingleOptional(char c)
{
	return c=='?';
}

static BOOL isMultiOptional(char c)
{
	return c=='*';
}

static unsigned long getLong(CString& strInput)
{
	const char *s = strInput.GetBufferSetLength(strInput.GetLength());
	char *firstInvalid = NULL;
	
	long dataH = strtol(s, &firstInvalid, 0);
	strInput.ReleaseBuffer();
	strInput.Delete(0, firstInvalid-s);
	strInput.TrimLeft();
	return (unsigned long) dataH;

}

static int getLongCheck(CString& strInput, unsigned long& outLong) 
{
	outLong = 0;
	
	strInput.TrimLeft();
	strInput.TrimRight();

	if (strInput.IsEmpty()) {
		return -1;
	}

	int len = strInput.GetLength();
	outLong = (unsigned long)getLong(strInput);
	if (len == strInput.GetLength()) {
		return -1;
	}
	return 0;
}

static int getB(CString& strInput, CU8Array& dataArr)
{
	unsigned long outLong = 0;
	if (getLongCheck(strInput, outLong) < 0) {
		return -1;
	}
	unsigned char data = (unsigned char)outLong;
	dataArr.Add(data);
	return 0;
}
//'H' stands for a short
static int getH(CString& strInput, CU8Array& dataArr)
{
	unsigned long outLong = 0;
	if (getLongCheck(strInput, outLong) < 0) {
		return -1;
	}

	unsigned short data = (unsigned short) outLong;
	//big endian or little endian?
	dataArr.Add(data&0xff);
	dataArr.Add(data>>8);
	return 0;
}

static int getI(CString& strInput, CU8Array& dataArr)
{

	unsigned long outLong = 0;
	if (getLongCheck(strInput, outLong) < 0) {
		return -1;
	}

	unsigned int data = (unsigned int)outLong;
	dataArr.Add(data&0xff);			//获取int的低位字节
	dataArr.Add((data>>8) & 0xff);	//获取int的第二个字节	
	dataArr.Add((data>>16) & 0xff);	//获取int的第三个字节
	dataArr.Add((data>>24) &0xff);	//获取int的第四个字节

	return 0;
}

static int getF(CString& strInput, CU8Array& dataArr)
{
	strInput.TrimLeft();
	strInput.TrimRight();

	FILE* fp = fopen(strInput, "rb");
	if (fp == NULL) {
		urgTrace("Error: %s open failed", (const char *)strInput);
		return -1;
	}

	fseek(fp, 0, SEEK_END);
	

	DWORD dwLength = ftell(fp);
	rewind(fp);
	char *buff = (char *)calloc(dwLength, 1);
	DWORD numRead = 0;
	
	for (;;) {
		numRead += fread(buff+numRead, 1, dwLength, fp);
		if (numRead == dwLength)
			break;
	}
	
	ASSERT(numRead == dwLength);
	for (DWORD i=0; i<dwLength; i++) {
		dataArr.Add(buff[i]);
	}
	free(buff);
	fclose(fp);
	return 0;
}

#define AppendFormat(s, fmt) do {		\
		CString tmp_asfd;		\
		tmp_asfd.Format fmt;		\
		s+=tmp_asfd;			\
	} while (0)

static CString getFormat(const char *dC /* i.e., inputSpec, such as "BB*" */)
{
	CString format;
	for (int i=0; dC[i]; i++) {
		if (dC[i]=='B' && notOptionalCode(dC[i+1])) {
				continue;
		} else if (dC[i]=='B' && isMultiOptional(dC[i+1])) {
			i++;
			format += "[string] ";
		} else if (dC[i]=='H' && isSingleOptional(dC[i+1])) {
			i++;
			format += "[uint16] ";
		} else if (dC[i]=='I' && isSingleOptional(dC[i+1])) {
			i++;
			format += "[uint32] ";
		} else if (dC[i]=='B' && isSingleOptional(dC[i+1])) {
			i++;
			format += "[uint8] ";
		} else if (dC[i]=='O' && notOptionalCode(dC[i+1])) {
			format += "[uint32 (as opcode)] [uint8]... ";
		} else if (dC[i]=='F' && notOptionalCode(dC[i+1])) {
			format += "[filename] ";
		} else if (dC[i]=='o' && notOptionalCode(dC[i+1])) {
			format += "[uint8]... ";
		}
	}

	if (format.IsEmpty()) {
		format += "no args";
	}
	format += "\r\n";
	return format;
}

static void commands()
{
	CString helpStr("\r\nCommands:\r\n--------------------------------\r\n\r\n");
	for (int i=0; cmdMap[i].cmdName!=NULL; i++) {
		CString cmdName(cmdMap[i].cmdName);
		AppendFormat(helpStr, ("%-25s : "
				       "opcode 0x%04x : "
				       "%s", cmdName, 
				       (unsigned short)cmdMap[i].opCode, 
				       getFormat(cmdMap[i].inputSpec)));
	}
	urgTrace("%s", helpStr);
	
}

static void help()
{
	CString helpStr("\r\nHelp:\r\n--------------------------------\r\n\r\n"
			"You can type the following to get more infomation:,\r\n"
			"\r\n"
			"        help: dislay this help\r\n"
			"        todo: display to-do in this tool\r\n"
			"        bugs: display bugs/defects known\r\n"
			"    commands: display a list of available commands\r\n"
			"\r\n"
			"When you type `commands`, the commands are displayed as `Command : Args`,\r\n"
			"Leading and trailing spaces in a command is ignored,\r\n"
			"  for e.g., `set keybl 255` is equal to `   set keybl    255   `\r\n"
			"but, space in a command is not,\r\n"
			"  for e.g., `get keybl` is ok, but `get  keybl` is not a valid command\r\n"
			"for those command that want one or more u8/u16/u32 argument, \r\n"
			"if none or less that required argument is supplied, a default 0 is used\r\n"
			"  for e.g., `set register 0x33 0x44` takes 2 args\r\n"
			"  0x33 is register number, 0x44 is the value, \r\n"
			"  i.e., register 0x33 will be set to 68 (decimal value of 0x44) \r\n"
			"  But, if you run `set register`, then register 0 will be set to 0\r\n"
			"And, you can use 0xf/017/15 to mean the same INT, 15.");
			

	urgTrace("%s", helpStr);
}

static void todo()
{
	CString todoStr("\r\nTodo:\r\n--------------------------------\r\n\r\n"
			"    1. make the interface more user-friendly\r\n"
			"       for e.g., get gpio should show if the i/o is pu/pd, etc.\r\n"
			"    2. implement a better help system\r\n"
			"    3. provide a means to clear or save the log to a file\r\n"
			"    4. provide a means to save the commands executed to a file\r\n"
			"    5. implement execution of commands from the saved commands file\r\n"
			"    6. fix bugs");
	urgTrace("%s", todoStr);
}

static void bugs()
{
	CString bugsStr("\r\nBugs:\r\n--------------------------------\r\n\r\n"
			"    1. connection is broken after you disconnect the usb cable\r\n"
			"       and must restart the application to reconnect\r\n"
			"    2. you must connect the usb cable before you start the application\r\n"
			"    3. many other bugs, some are even undiscovered yet\r\n"
			"       Please help report bugs/suggestions to [email protected]");
	urgTrace("%s", bugsStr);
}


static void printResult(CU8Array& result)
{
	CString recvTrace("\"");
	if (result.GetSize()==0) {
		return;
	}

	for (int k=0; k<result.GetSize(); k++) {
		if (isprint(result[k])) {
			recvTrace += result[k];
		} else {
			CString tmp;
			tmp.Format("\\x%02x", result[k]);
			recvTrace += tmp;
		}
	}
	recvTrace+='"';

	urgTrace("%s", recvTrace);

	recvTrace = "   in hex: ";
	for (k=0; k<result.GetSize(); k++) {
		CString tmp;
		tmp.Format("0x%02x ", result[k]);
		recvTrace += tmp;
	}
	dbgTrace("%s", recvTrace);
								   
	return;
}

static BOOL isFromUser(char where)
{
	return where == '>';
}

static BOOL isFromFixed(char where)
{
	return where == '<';
}

static BOOL isArbitrary(char where)
{
	return where == '!';
}

static BOOL isMultiple(char where)
{
	return where == '*';
}

static int getArg(CU8Array& dataArr, CString& strUserInput, CString& strFixedInput, char dataType, char where)
{
	if (dataType == 'B') {
		if (isFromUser(where)) {
			return getB(strUserInput, dataArr);
		} else if (isFromFixed(where)) {
			return getB(strFixedInput, dataArr);
		} else if (isArbitrary(where)) {
			return getB(CString("0"), dataArr);
		} else if (isMultiple(where)) { //the rest of the user-input is consumed

			for (int k=0; k<strUserInput.GetLength(); k++) {
				dataArr.Add(strUserInput[k]);
			}
			strUserInput = ""; //empty user-input
			return 0;
		}
	} else if (dataType == 'H') {
		if (isFromUser(where)) {
			return getH(strUserInput, dataArr);
		} else if (isFromFixed(where)) {
			return getH(strFixedInput, dataArr);
		} else if (isArbitrary(where)) {
			return getH(CString("0"), dataArr);
		} else {
			urgTrace("Error: alchemy bug detected, code is %c %c", dataType, where);
			return -1;
		}
	} else if (dataType == 'I') {
		if (isFromUser(where)) {
			return getI(strUserInput, dataArr);
		} else if (isFromFixed(where)) {
			return getI(strFixedInput, dataArr);
		} else if (isArbitrary(where)) {
			return getI(CString("0"), dataArr);
		} else {
			urgTrace("Error: alchemy bug detected, code is %c %c", dataType, where);
			return -1;
		}
	} else if (dataType == 'o') {
		strUserInput.TrimLeft();
		CString savedCommand = strUserInput;
					
		for (int k=0;;k++) { //infinite loop, k is only for debugging
			if (strUserInput.IsEmpty()) {
				break;
			}
			getB(strUserInput, dataArr);
			if (strUserInput == savedCommand) {
				urgTrace("invalid arguments, `%s'", savedCommand);
				return -1;
			}
			strUserInput.TrimLeft();
			savedCommand = strUserInput;
		}
		
		return 0;
	} else if (dataType == 'F') {
		if (!isFromUser(where)) {
			urgTrace("Error: alchemy bug detected, code is %c %c", dataType, where);
		}				
		return getF(strUserInput, dataArr);
	} else {
		urgTrace("Error: alchemy bug detected, code is %c %c", dataType, where);
		return -1;
	}

	return 0;
}

int cliCarryOut(const char *sCommand)
{
	return cliCarryOut(CString(sCommand));
}

int cliCarryOut(const CString& sCommand)
{
	CU8Array result;
	return cliCarryOut(sCommand, result);
}

//resolve the command send by IDC_EXEC_COMMAND
int cliCarryOut(const CString& sCommandConst, CU8Array& result)
{
	if (alchemyInited == FALSE) {
		urgTrace("Must call InitAlchemyLib first!\n");
		return -1;
	}

	//we need to change the input string, so make a copy to remove the `const'
	CString sCommand = sCommandConst;
	sCommand.TrimLeft();
	sCommand.TrimRight();
	
	for (int i=0; cmdMap[i].cmdName; i++) {
		if (sCommand.Find(cmdMap[i].cmdName) == 0) {
			const char *inputSpec = cmdMap[i].inputSpec;
			const char *fixedInput = cmdMap[i].fixedInput;
			int opcode = cmdMap[i].opCode;  // this will change if cmd is "opcode"
			
			//so that only args to the cmd is in sCommand
			sCommand.Delete(0, strlen(cmdMap[i].cmdName));
			sCommand.TrimLeft();
			
			CString strUserInput = sCommand;
			CString strFixedInput = fixedInput? fixedInput : "";
			
			CU8Array dataArr; //empty at first

			//handle opcode first:
			if (opcode < 0) {
				opcode = getLong(strUserInput);
			}
			
			for (int j=0; inputSpec[j]; j=j+2) {
				int n = getArg(dataArr, strUserInput, strFixedInput, inputSpec[j], inputSpec[j+1]);

				if (n < 0) {
					urgTrace("Error: don't know how to parse the input string:\n    %s", (const char*)sCommandConst);
				}
			} 

			if (strUserInput.GetLength()) {
				urgTrace("Error: argument parse failed, `%s' is remaining in the command string", strUserInput);
				return -1;
			}

			BYTE recv[1024] = {0};
			int nRecv = 0;

			CString sendTrace("send: \"opCode ");
			CString tmp;
			tmp.Format("0x%08x,data: ", opcode);
			sendTrace+=tmp;
			for (int k=0; k<min(10,dataArr.GetSize()); k++) {
				CString tmp;
				tmp.Format("0x%02x ", dataArr[k]);
				sendTrace+=tmp;
			}
			if (dataArr.GetSize()>10) {
				sendTrace+="...";
			}
			dbgTrace("%s", sendTrace);

			int ret = getConnection()->UC_Do3rdCommand(opcode,
								   dataArr,
								   result,
								   cmdMap[i].cmdName);
			printResult(result);
			if (ret < 0) {
				infoTrace("`%s`: failed!", cmdMap[i].cmdName);
				return -1;
			} else {
				infoTrace("`%s`: success!", cmdMap[i].cmdName);
				return 0;
			}
		}
	}
	if (sCommand.Find("help") == 0) {
		help();
	} else if (sCommand.Find("todo") == 0) {
		todo();
	} else if (sCommand.Find("bugs") == 0) {
		bugs();
	} else if (sCommand.Find("commands") == 0) {
		commands();
	} else {
		urgTrace("%s", sCommand+=": unknown command");
	} 
	return 0;
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.