Create Email address from names Compiler Design - flex4

Creating email addresses form names
You have given a file containing names of several persons. The file will have exactly one name is each line. You need to create email address ending with #bitmesra.ac.in from those names.
the rule for creating email address is defined below: A name will be expressed in the following form:
............
Let F(s) denote the first character of string s.
so, email id will be F(string 1)F(string 2)........._lastString#bitmesra.ac.in
Some names and their corresponding email id's are listed below as an example
Sachin Ramesh Tendulkar s_r_tendulkar#bitmesra.ac.in
Rahul S Dravid r_s_dravid#bitmesra.ac.in
You need to generate a grammer for this.
note: there may multiple spaces b/w names.
My Code is here
#include<cstdio>
#include<cstring>
#include<cctype>
int main()
{
char str1[100],str2[100];
char str3[] = "#bitmesra.ac.in";
while(gets(str1))
{
int index,k=0;
str2[k] = tolower(str1[0]);
for(int i=1;i<strlen(str1);i++)
{
if(str1[i]==' ')
{
index = i;
if(isalpha(str1[i+1]))
{
k++;
str2[k] = '_';
k++;
str2[k] = tolower(str1[i+1]);
}
}
}
index= index + 2;
for(int i=index;str1[i]!='\0';i++)
{
k++;
str2[k] = tolower(str1[i]);
}
str2[++k] = '\0';
strcat(str2,str3);
printf("%s\n",str2);
}
return 0;
}
How to write CFG Grammar For this.....

What about something like:
optnamelist: /* file can be empty */
| namelist /* do nothing */
namelist: nameseq NL /* process vector */
| namelist NL nameseq /* process vector */
nameseq: name /* create vector and add element 1 */
| nameseq name /* add element to vector */
The lexer should take care of white spaces (eat them). The NL token is a sequence of one or more newlines.
If you add names to the end of a vector, you'll have to process it backward.
Your code implies you're writing this in C. So you could use a fixed sized Vector, e.g.
#define MAX_NAMES 100 /* this will probably be enough :-) */
static int actpos;
static char *myVector[MAX_NAMES];
...
/* "create" vector */
memset(myVector, 0, MAX_NAMES * sizeof(char *));
actpos = 0;
...
/* add name to vector */
myVector[actpos] = strdup($1 /* or $2 */);
if (myVector[actpos) == NULL) ... /* out of memory */
actpos++;
if (actpos >= MAX_NAMES) ... /* name too long */
...
/* process vector */
for (i = actpos - 1; i > 0; --i) {
/* add myVector[i][0] to e-mail address */
free(myVector[i]);
}
/* add myVector[0] to e-mail address */
free(myVector[0]);

Related

Reading binary data

I am trying to read data from a binary file. One block of data is 76 bytes long (this varies with the number of the 2-byte "main data items" in the middle of the block). The first datum is 4 bytes, second is 4 bytes, and then there are a bunch of 2 byte main data items, and at the end are 2 more 2-byte pieces of data.
Based on this Delphi sample I've learned how to read the file with the code below:
short AShortInt; // 16 bits
int AInteger; // 32 bits
try
{
infile=new TFileStream(myfile,fmOpenRead); // myfile is binary
BR = new TBinaryReader(infile, TEncoding::Unicode, false);
for (int rows = 0; rows < 5; rows++) { // just read the first 5 blocks of data for testing
AInteger = BR->ReadInt32(); // read first two 4 byte integers for this block
AInteger = BR->ReadInt32();
for (int i = 0; i < 32; i++) { // now read the 32 2-byte integers from this block
AShortInt = BR->ReadInt16();
}
AShortInt = BR->ReadInt16(); // read next to last 2-byte int
AShortInt = BR->ReadInt16(); // read the last 2-byte int
}
delete infile;
delete BR;
Close();
}
catch(...)
{
delete infile; // closes the file, doesn't delete it.
delete BR;
ShowMessage("Can't open file!");
Close();
}
But, what i would like to do is use a 76-byte wide buffer to read the entire block, and then pick the various datum out of that buffer. I put together the following code based on this question and i can read a whole block of data into the buffer.
UnicodeString myfile = System::Ioutils::TPath::Combine(System::Ioutils::TPath::GetDocumentsPath(), "binaryCOM.dat");
TFileStream*infile=0;
try
{
infile=new TFileStream(myfile,fmOpenRead);
const int bufsize=76;
char*buf=new char[bufsize];
int a = 0;
while(int bytesread=infile->Read(buf,bufsize)) {
a++; // just a place to break on Run to Cursor
}
delete[]buf;
}
catch(...)
{
delete infile;
ShowMessage("Can't open file!");
Close();
}
But i can't figure out how to piece together subsets out of the bytes in the buffer. Is there a way to concatenate bytes? So i could read a block of data into a 76 byte buffer and then do something like this below?
unsigned int FirstDatum = buf[0]+buf[1]+buf[2]+buf[3]; // concatenate the 4 bytes for the first piece of data
This will be an FMX app for Win32, iOS, and Android built in C++Builder 10.3.2.
Here is my modified code using Remy's suggestion of TMemoryStream.
UnicodeString myfile = System::Ioutils::TPath::Combine(System::Ioutils::TPath::GetDocumentsPath(), "binaryCOM.dat");
TMemoryStream *MS=0;
TBinaryReader *BR=0;
std::vector<short> myArray;
short AShortInt;
int AInteger;
int NumDatums = 32; // the variable number of 2-byte main datums
try
{
MS = new TMemoryStream();
MS->LoadFromFile(myfile);
BR = new TBinaryReader(MS, TEncoding::Unicode, false);
for (int rows = 0; rows < 5; rows++) { // testing with first 5 blocks of data
AInteger = BR->ReadInt32(); // read first two 4 byte integers
AInteger = BR->ReadInt32(); // here
for (int i = 0; i < NumDatums; i++) { // read the main 2-byte data
AShortInt = BR->ReadInt16();
myArray.push_back(AShortInt); // push it into vector
}
AShortInt = BR->ReadInt16(); // read next to last 2-byte int
AShortInt = BR->ReadInt16(); // read the last 2-byte int
// code here to do something with this block of data just read from file
}
}
delete MS;
delete BR;
}
catch(...)
{
delete MS;
delete BR;
ShowMessage("Can't open file.");
}

Convert connect address with address familiy AF_SYSTEM to human readable string

Background
I'm writing some dtrace program which tracks application socket file descriptors. Aim is to provide logs which help me spot leak of file descriptors in some very complex OS X application.
Here is my other question with very helpful answer.
Problem
I want that my program is logging address to which file descriptor has been connected to. In examples there is a code which partial do what I need: soconnect_mac.d, here is link to github.
soconnect_mac.d works great when applied on Firefox, but it completely fails in case of my application. Quick investigation shown that soconnect_mac.d is able to interpret only AF_INET (value 2) family address and som library used by my application is using AF_SYSTEM (value 32) family address.
I can't find anything which could help me convert received address to something what is human readable.
So far I've got this:
#!/usr/sbin/dtrace -s
inline int af_inet = 2 ; /* AF_INET defined in Kernel/sys/socket.h */
inline int af_inet6 = 30; /* AF_INET6 defined in Kernel/sys/socket.h */
inline int af_system = 32; /* AF_SYSTEM defined in Kernel/sys/socket.h */
… // some stuff
syscall::connect:entry
/pid == $target && isOpened[pid, arg0] == 1/
{
/* assume this is sockaddr_in until we can examine family */
this->s = (struct sockaddr_in *)copyin(arg1, arg2);
this->f = this->s->sin_family;
self->fileDescriptor = arg0;
}
/* this section is copied with pride from "soconnect_mac.d" */
syscall::connect:entry
/this->f == af_inet/
{
/* Convert port to host byte order without ntohs() being available. */
self->port = (this->s->sin_port & 0xFF00) >> 8;
self->port |= (this->s->sin_port & 0xFF) << 8;
/*
* Convert an IPv4 address into a dotted quad decimal string.
* Until the inet_ntoa() functions are available from DTrace, this is
* converted using the existing strjoin() and lltostr(). It's done in
* two parts to avoid exhausting DTrace registers in one line of code.
*/
this->a = (uint8_t *)&this->s->sin_addr;
this->addr1 = strjoin(lltostr(this->a[0] + 0ULL),
strjoin(".",
strjoin(lltostr(this->a[1] + 0ULL),
".")));
this->addr2 = strjoin(lltostr(this->a[2] + 0ULL),
strjoin(".",
lltostr(this->a[3] + 0ULL)));
self->address = strjoin(this->addr1, this->addr2);
}
/* this section is my */
syscall::connect:entry
/this->f == af_system/
{
/* TODO: Problem how to handle AF_SYSTEM address family */
/* Convert port to host byte order without ntohs() being available. */
self->port = (this->s->sin_port & 0xFF00) >> 8;
self->port |= (this->s->sin_port & 0xFF) << 8; // this also doen't work as it should
self->address = "system family address needed here";
}
// a fallback
syscall::connect:entry
/this->f && this->f != af_inet && this->f != af_system/
{
/* Convert port to host byte order without ntohs() being available. */
self->port = (this->s->sin_port & 0xFF00) >> 8;
self->port |= (this->s->sin_port & 0xFF) << 8;
self->address = strjoin("Can't handle family: ", lltostr(this->f));
}
syscall::connect:return
/self->fileDescriptor/
{
this->errstr = err[errno] != NULL ? err[errno] : lltostr(errno);
printf("%Y.%03d FD:%d Status:%s Address:%s Port:%d",
walltimestamp, walltimestamp % 1000000000 / 1000000,
self->fileDescriptor, this->errstr, self->address, self->port);
self->fileDescriptor = 0;
self->address = 0;
self->port = 0;
}
What is even more annoying my code has failed to read port number (I get 512 value instead one of this: 443, 8443, 5061).
IMO problem is first syscall::connect:entry where it is assumed that second argument can be treated as struct sockaddr_in. I'm guessing struct sockaddr_storage should be used in case of AF_SYSTEM address family, but I didn't found any documentation or source code which proves this in direct way.
My section with this->f == af_system condition properly catches events from application I'm investigating.

STM32F429 FMC SDRAM issue when column adress > 8bit

I have the issue with FMC controller when interfacing 64MB IS42S16400J-7BLI.
I'm using the CubeMX to set base configuration
static void MX_FMC_Init(void)
{
FMC_SDRAM_TimingTypeDef SdramTiming;
/** Perform the SDRAM1 memory initialization sequence
*/
hsdram1.Instance = FMC_SDRAM_DEVICE;
/* hsdram1.Init */
hsdram1.Init.SDBank = FMC_SDRAM_BANK1;
hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_11;
hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12;
hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16;
hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
hsdram1.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_3;
hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;
hsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_DISABLE;
hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0;
/* SdramTiming */
SdramTiming.LoadToActiveDelay = 2;
SdramTiming.ExitSelfRefreshDelay = 7;
SdramTiming.SelfRefreshTime = 4;
SdramTiming.RowCycleDelay = 7;
SdramTiming.WriteRecoveryTime = 3;
SdramTiming.RPDelay = 2;
SdramTiming.RCDDelay = 2;
if (HAL_SDRAM_Init(&hsdram1, &SdramTiming) != HAL_OK)
{
Error_Handler();
}
}
and config the memory
void SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef* hsdram, FMC_SDRAM_CommandTypeDef* Command)
{
__IO uint32_t tmpmrd = 0;
/* Step 3: Configure a clock configuration enable command */
Command->CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command->AutoRefreshNumber = 1;
Command->ModeRegisterDefinition = 0;
/* Send the command */
HAL_SDRAM_SendCommand(hsdram, Command, 0x1000);
/* Step 4: Insert 100 ms delay */
HAL_Delay(100);
/* Step 5: Configure a PALL (precharge all) command */
Command->CommandMode = FMC_SDRAM_CMD_PALL;
Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command->AutoRefreshNumber = 1;
Command->ModeRegisterDefinition = 0;
/* Send the command */
HAL_SDRAM_SendCommand(hsdram, Command, 0x1000);
/* Step 6 : Configure a Auto-Refresh command */
Command->CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command->AutoRefreshNumber = 4;
Command->ModeRegisterDefinition = 0;
/* Send the command */
HAL_SDRAM_SendCommand(hsdram, Command, 0x1000);
/* Step 7: Program the external memory mode register */
tmpmrd = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_2 |
SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL |
SDRAM_MODEREG_CAS_LATENCY_3 |
SDRAM_MODEREG_OPERATING_MODE_STANDARD |
SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;
Command->CommandMode = FMC_SDRAM_CMD_LOAD_MODE;
Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command->AutoRefreshNumber = 1;
Command->ModeRegisterDefinition = tmpmrd;
/* Send the command */
HAL_SDRAM_SendCommand(hsdram, Command, 0x1000);
/* Step 8: Set the refresh rate counter */
/* (15.62 us x Freq) - 20 */
/* Set the device refresh counter */
HAL_SDRAM_ProgramRefreshRate(hsdram, REFRESH_COUNT);
}
The memory and micro are connected according to the schematic
I can use only 8bit of addressing. In this configuration everything is perfect, i.e. I can read/write values and observe them in debug window. It limits me though to only 8MB of memory.
When I modify in settings 8bits up to 9/10/11bits to have more memory available it starts malfunctioning,i.e. garbage in some memory area.
I made customized board, but the same issue you going find on the STM32F429-disco board. So I reject rather the connections. I tried to play with the time delays like "Row to column delay" and increase all delays possible, but not luck. Any help would be appreciated.
From IS42S16400J-7BLI datasheet:
Internally configured as a quad-bank DRAM with a synchronous
interface. Each 16,777,216-bit bank is organized as 4,096 rows by 256
columns by 16 bits.
So, you should use 8 bit in ColumnBitsNumber. And you'll get 8 Mbytes (64 MBits/8) of memory.

Attempted to read or write protected memory when accessing dll

I try to access zip32.dll version 3.0 when my code got this error :
System.AccessViolationException: Attempted to read or write protected memory.
This is often an indication that other memory is corrupt.
at projectName.clsName.ZpArchive(ZCL& zcl, ZPOPT& zopts)
at projectName.clsName.functionName() in <location>:<line>
This is what i done with the code :
//ZCL Structures
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
protected struct ZCL
{
public int argc; /* Count of files to zip */
[MarshalAs(UnmanagedType.LPStr)]
public string fzname; /* name of archive to create/update */
public string[] zipnames; /* zip file name */
[MarshalAs(UnmanagedType.LPStr)]
public string fzlist; /* name of archive to create/update */
}
//ZPOPT Structures
[ StructLayout( LayoutKind.Sequential )]
protected struct ZPOPT
{
[MarshalAs(UnmanagedType.LPTStr)]
public string Date; // US Date (8 Bytes Long) "12/31/98"?
[MarshalAs(UnmanagedType.LPTStr)]
public string szRootDir; // Root Directory Pathname (Up To 256 Bytes Long)
[MarshalAs(UnmanagedType.LPTStr)]
public string szTempDir; // Temp Directory Pathname (Up To 256 Bytes Long)
public int fTemp; // 1 If Temp dir Wanted, Else 0
public int fSuffix; // Include Suffixes (Not Yet Implemented!)
public int fEncrypt; // 1 If Encryption Wanted, Else 0
public int fSystem; // 1 To Include System/Hidden Files, Else 0
public int fVolume; // 1 If Storing Volume Label, Else 0
public int fExtra; // 1 If Excluding Extra Attributes, Else 0
public int fNoDirEntries; // 1 If Ignoring Directory Entries, Else 0
public int fExcludeDate; // 1 If Excluding Files Earlier Than Specified Date, Else 0
public int fIncludeDate; // 1 If Including Files Earlier Than Specified Date, Else 0
public int fVerbose; // 1 If Full Messages Wanted, Else 0
public int fQuiet; // 1 If Minimum Messages Wanted, Else 0
public int fCRLF_LF; // 1 If Translate CR/LF To LF, Else 0
public int fLF_CRLF; // 1 If Translate LF To CR/LF, Else 0
public int fJunkDir; // 1 If Junking Directory Names, Else 0
public int fGrow; // 1 If Allow Appending To Zip File, Else 0
public int fForce; // 1 If Making Entries Using DOS File Names, Else 0
public int fMove; // 1 If Deleting Files Added Or Updated, Else 0
public int fDeleteEntries; // 1 If Files Passed Have To Be Deleted, Else 0
public int fUpdate; // 1 If Updating Zip File-Overwrite Only If Newer, Else 0
public int fFreshen; // 1 If Freshing Zip File-Overwrite Only, Else 0
public int fJunkSFX; // 1 If Junking SFX Prefix, Else 0
public int fLatestTime; // 1 If Setting Zip File Time To Time Of Latest File In Archive, Else 0
public int fComment; // 1 If Putting Comment In Zip File, Else 0
public int fOffsets; // 1 If Updating Archive Offsets For SFX Files, Else 0
public int fPrivilege; // 1 If Not Saving Privileges, Else 0
public int fEncryption; // Read Only Property!!!
public int fRecurse; // 1 (-r), 2 (-R) If Recursing Into Sub-Directories, Else 0
public int fRepair; // 1 = Fix Archive, 2 = Try Harder To Fix, Else 0
public byte flevel; // Compression Level - 0 = Stored 6 = Default 9 = Max
[MarshalAs(UnmanagedType.LPTStr)]
public string fSplitSize; //Null for no spliting size
//addition for ZCL
public int m_CountFile; //For total file on backup file.
}
//Import Dll:
[DllImport("zip32.dll", SetLastError=true)]
protected static extern int ZpArchive(ref ZCL zcl,ref ZPOPT zopts);
And here's the function that call the ZpArchive :
//set the zip options
m_zopts = CreateZPOPTOptions();
ZCL zcl = new ZCL();
zcl.argc = m_CountFile; //Total file
zcl.fzname = m_ZipFileName;
zcl.zipnames = m_FilesToZip;
zcl.fzlist = null;
//zip the files
try
{
ret = ZpArchive(ref zcl,ref m_zopts);
}
catch(Exception e)
{
//<catch>
}
The exception threw when i try to call the ZpArchive function.
I'm using Visual Studio 2010 with compatibility for .Net 2.0
Any idea / advise regarding to this issue?
Thanks in advance :) -FDI
Update :
Here's the structure from library source code :
typedef struct { /* zip options */
LPSTR Date; /* Date to include after */
LPSTR szRootDir; /* Directory to use as base for zipping */
LPSTR szTempDir; /* Temporary directory used during zipping */
BOOL fTemp; /* Use temporary directory '-b' during zipping */
BOOL fSuffix; /* include suffixes (not implemented) */
BOOL fEncrypt; /* encrypt files */
BOOL fSystem; /* include system and hidden files */
BOOL fVolume; /* Include volume label */
BOOL fExtra; /* Exclude extra attributes */
BOOL fNoDirEntries; /* Do not add directory entries */
BOOL fExcludeDate; /* Exclude files newer than specified date */
BOOL fIncludeDate; /* Include only files newer than specified date */
BOOL fVerbose; /* Mention oddities in zip file structure */
BOOL fQuiet; /* Quiet operation */
BOOL fCRLF_LF; /* Translate CR/LF to LF */
BOOL fLF_CRLF; /* Translate LF to CR/LF */
BOOL fJunkDir; /* Junk directory names */
BOOL fGrow; /* Allow appending to a zip file */
BOOL fForce; /* Make entries using DOS names (k for Katz) */
BOOL fMove; /* Delete files added or updated in zip file */
BOOL fDeleteEntries; /* Delete files from zip file */
BOOL fUpdate; /* Update zip file--overwrite only if newer */
BOOL fFreshen; /* Freshen zip file--overwrite only */
BOOL fJunkSFX; /* Junk SFX prefix */
BOOL fLatestTime; /* Set zip file time to time of latest file in it */
BOOL fComment; /* Put comment in zip file */
BOOL fOffsets; /* Update archive offsets for SFX files */
BOOL fPrivilege; /* Use privileges (WIN32 only) */
BOOL fEncryption; /* TRUE if encryption supported, else FALSE.
this is a read only flag */
LPSTR szSplitSize; /* This string contains the size that you want to
split the archive into. i.e. 100 for 100 bytes,
2K for 2 k bytes, where K is 1024, m for meg
and g for gig. If this string is not NULL it
will automatically be assumed that you wish to
split an archive. */
LPSTR szIncludeList; /* Pointer to include file list string (for VB) */
long IncludeListCount; /* Count of file names in the include list array */
char **IncludeList; /* Pointer to include file list array. Note that the last
entry in the array must be NULL */
LPSTR szExcludeList; /* Pointer to exclude file list (for VB) */
long ExcludeListCount; /* Count of file names in the include list array */
char **ExcludeList; /* Pointer to exclude file list array. Note that the last
entry in the array must be NULL */
int fRecurse; /* Recurse into subdirectories. 1 => -r, 2 => -R */
int fRepair; /* Repair archive. 1 => -F, 2 => -FF */
char fLevel; /* Compression level (0 - 9) */
} ZPOPT, _far *LPZPOPT;
typedef struct {
int argc; /* Count of files to zip */
LPSTR lpszZipFN; /* name of archive to create/update */
char **FNV; /* array of file names to zip up */
LPSTR lpszAltFNL; /* pointer to a string containing a list of file
names to zip up, separated by whitespace. Intended
for use only by VB users, all others should set this
to NULL. */
} ZCL, _far *LPZCL;
and the function declaration :
int EXPENTRY ZpArchive(ZCL C, LPZPOPT Opts);
some forum said it's because of umanageable code. I already use MarshalAs but still not working..

Jump to listbox item by typing first few characters

I have a list of items (potentially large) from which the user must select one. I'd like to allow the user to type the first few letters of the desired item to jump to the correct place in the list. By default, each keypress jumps to the first item starting with that letter, so you can't type the first several letters. Is there any straightforward way to do this? Any CodeProject or other such example?
I've looked for hours, and found any number of samples for IAutocomplete, but that won't help here because I need to guarantee that the result is in the list.
The only way I can think to do this is to derive from CListBox, capture the keystrokes myself, find the item, run a timer so that new keystrokes after a sufficient pause will start a new search... since I'm not an MFC jock, this is daunting. Any tips much appreciated.
One clarifying note: my ultimate goal is actually to get this keyboard behavior for a ComboBox of DropDownList style (i.e. no edit box). The lack of an edit box rules out most autocomplete code, and the need for ComboBox functionality means I can't use CListCtrl by itself.
After much unnecessary pain, I've discovered that the real correct answer is simply to use LBS_SORT. Simply by specifying this style, the basic vanilla listbox supports the incremental search keyboard shortcut style I wanted. Without LBS_SORT (or CBS_SORT for a combobox), you get the irritating and almost-useless jump-to-first-letter-only behavior. I didn't try LBS_SORT because my list contents were added in sorted order anyway.
So the dozen or so hours of investigating custom controls, etc., all for naught because the Microsoft documentation makes no mention of this important behavioral difference in the description of LBS_SORT!!
Thanks to everyone who contributed.
I've implemented such a functionality in core Win32. Heres the code.
Somewhere in your message loop that processes the list box insert:
switch(message)
{
case WM_CHAR:
if(HandleListBoxKeyStrokes(hwnd, wParam) == FALSE)
return FALSE;
....
Heres the code (propably not fully complete):
/* ======================================================================== */
/* ======================================================================== */
#define RETURNr(a, b) // homegrown asserts
BOOLEAN HandleListBoxKeyStrokes(HWND hwnd, UINT theKey)
{
#define MAXCHARCACHEINTERVALL 600.0 // Max. milisecs time offset to consider as typed 'at once'
static char sgLastChars[255] = {'0'};
static double sgLastCharTime = 0.;
static HWND sgLasthwnd = NULL;
if(GetSecs() - sgLastCharTime > MAXCHARCACHEINTERVALL ||
sgLasthwnd != hwnd)
*sgLastChars = 0;
if(theKey == ' ' && *sgLastChars == 0)
return TRUE;
sgLastCharTime = GetSecs();
sgLasthwnd = hwnd;
AppendChar(sgLastChars, toupper(theKey));
if(strlen(sgLastChars) > 1)
{
LONG l = GetWindowLong(hwnd, GWL_STYLE);
Char255 tx;
GetClassName(hwnd, tx, sizeof(tx));
if( (! stricmp(tx, "Listbox") &&
! (l & (LBS_EXTENDEDSEL | LBS_MULTIPLESEL)) ) ||
(! stricmp(tx, "ComboBox") && // combo Box support
l & CBS_DROPDOWNLIST &&
! (l & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) ) )
{
long Count, l, BestMatch = - 1, BestMatchOff = 0;
long LBcmdSet[] = {LB_GETCOUNT, LB_GETTEXTLEN , LB_GETTEXT};
long CBcmdSet[] = {CB_GETCOUNT, CB_GETLBTEXTLEN, CB_GETLBTEXT};
long *cmdSet = (! stricmp(tx, "ComboBox")) ? CBcmdSet : LBcmdSet;
RETURNr((Count = SendMessage(hwnd, cmdSet[0], 0, 0)) != LB_ERR, 0);
for(int i = 0; i < Count; i++)
{
RETURNr((l = SendMessage(hwnd, cmdSet[1], i, 0)) != LB_ERR, TRUE);
RETURNr( l < sizeof(tx), TRUE);
RETURNr((l = SendMessage(hwnd, cmdSet[2], i, (LPARAM)&tx)) != LB_ERR, TRUE);
strupr(tx);
if(! strncmp(tx, sgLastChars, strlen(sgLastChars)))
{
SelListBoxAndNotify(hwnd, i);
return FALSE;
}
char *p;
if(p = strstr(tx, sgLastChars))
{
int off = p - tx;
if(BestMatch == -1 || off < BestMatchOff)
{
BestMatch = i;
BestMatchOff = off;
}
}
}
// If text not found at start of string see if it matches some part inside the string
if(BestMatch != -1)
SelListBoxAndNotify(hwnd, BestMatch);
// Nothing found - dont process
return FALSE;
}
}
return TRUE;
}
/* ======================================================================== */
/* ======================================================================== */
void SelListBoxAndNotify(HWND hwnd, int index)
{
// i am sorry here - this is some XVT-toolkit specific code.
// it has to be replaced with something similar for native Win32
WINDOW win = xvtwi_hwnd_to_window(hwnd);
WINDOW parent = xvt_vobj_get_parent(win);
xvt_list_set_sel(win, index, 1);
EVENT evt;
memset(&evt, 0, sizeof(evt));
evt.type = E_CONTROL;
evt.v.ctl.id = GetDlgCtrlID(hwnd);
evt.v.ctl.ci.v.lbox.dbl_click = FALSE;
xvt_win_dispatch_event(parent, &evt);
}
/* ======================================================================== */
/* ======================================================================== */
double GetSecs(void)
{
struct timeb timebuffer;
ftime(&timebuffer);
return (double)timebuffer.millitm +
((double)timebuffer.time * 1000.) - // Timezone needed for DbfGetToday
((double)timebuffer.timezone * 60. * 1000.);
}
/* ======================================================================== */
/* ======================================================================== */
char AppendChar(char *tx, char C)
{ int i;
i = strlen(tx);
tx[i ] = C;
tx[i + 1] = 0;
return(C);
}
Can you use a CListView CListCtrl instead? They work like that by default.

Resources