Setting NULL causes lag with [MAX_STRING_LENGTH] = {'\0'}; - c++

I thought it would be a good best practice to search thru my code for any references like ..
char buf[MAX_STRING_LENGTH];
... and replace them with ...
char buf[MAX_STRING_LENGTH] = {'\0'};
Doing a search in the code I have a number that are set to null (around 239) and others that are not (1,116).
When I replaced the remaining 1,116 instances with char buf[MAX_STRING_LENGTH] = {'\0'}; and pushed the code live the game was noticeably laggy.
Reverting the change removed the lag.
Can someone explain why setting these to null would cause the game to lag while running?
Example code setting to Null
void do_olist(Character *ch, char *argument, int cmd)
{
int header = 1;
int type = -1;
int wear_bit = -1;
int i = 0;
int inclusive;
int zone = -1;
int yes_key1 = 0;
int yes_key2 = 0;
int yes_key3 = 0;
int count = 0;
Object *obj;
bool found = false;
char key1 [MAX_STRING_LENGTH] = {'\0'};
char key2 [MAX_STRING_LENGTH] = {'\0'};
char key3 [MAX_STRING_LENGTH] = {'\0'};
char buf [MAX_STRING_LENGTH];
argument = one_argument(argument, buf);
if (!*buf)
{
ch->send("Selection Parameters:\n\n");
ch->send(" +/-<object keyword> Include/exclude object keyword.\n");
ch->send(" <zone> Objects from zone only.\n");
ch->send(" <item-type> Include items of item-type.\n");
ch->send(" <wear-bits> Include items of wear type.\n");
ch->send("\nExample: olist +sword -rusty weapon 10\n");
ch->send("will only get non-rusty swords of type weapon from zone 10.\n");
return;
}
while (*buf)
{
inclusive = 1;
if (strlen(buf) > 1 && isalpha(*buf) &&
(type = index_lookup(item_types, buf)) != -1)
{
argument = one_argument(argument, buf);
continue;
}
if (strlen(buf) > 1 && isalpha(*buf) &&
(wear_bit = index_lookup(wear_bits, buf)) != -1)
{
argument = one_argument(argument, buf);
continue;
}
if (isdigit(*buf))
{
if ((zone = atoi(buf)) >= MAX_ZONE)
{
ch->send("Zone not in range 0..99\n");
return;
}
argument = one_argument(argument, buf);
continue;
}
switch (*buf)
{
case '-':
inclusive = 0;
case '+':
if (!buf [1])
{
ch->send("Expected keyname after 'k'.\n");
return;
}
if (!*key1)
{
yes_key1 = inclusive;
strcpy(key1, buf + 1);
}
else if (!*key2)
{
yes_key2 = inclusive;
strcpy(key2, buf + 1);
}
else if (*key3)
{
ch->send("Sorry, at most three keywords.\n");
return;
}
else
{
yes_key3 = inclusive;
strcpy(key3, buf + 1);
}
break;
case 'z':
argument = one_argument(argument, buf);
if (!isdigit(*buf) || atoi(buf) >= MAX_ZONE)
{
ch->send("Expected valid zone after 'z'.\n");
return;
}
zone = atoi(buf);
break;
}
argument = one_argument(argument, buf);
}
*b_buf = '\0';
for (obj = full_object_list; obj; obj = obj->lnext)
{
if (zone != -1 && obj->zone != zone)
continue;
if (type != -1 && obj->obj_flags.type_flag != type)
continue;
if (wear_bit != -1)
{
for (i = 0; (*wear_bits[i] != '\n'); i++)
{
if (IS_SET(obj->obj_flags.wear_flags, (1 << i)))
{
if (i != wear_bit)
continue;
else
found = true;
}
}
if (found)
found = false;
else
continue;
}
if (*key1)
{
if (yes_key1 && !strcasestr(const_cast<char*> (obj->getName().c_str()), key1))
continue;
else if (!yes_key1 && strcasestr(const_cast<char*> (obj->getName().c_str()), key1))
continue;
}
if (*key2)
{
if (yes_key2 && !strcasestr(const_cast<char*> (obj->getName().c_str()), key2))
continue;
else if (!yes_key2 && strcasestr(const_cast<char*> (obj->getName().c_str()), key2))
continue;
}
if (*key3)
{
if (yes_key3 && !strcasestr(const_cast<char*> (obj->getName().c_str()), key3))
continue;
else if (!yes_key3 && strcasestr(const_cast<char*> (obj->getName().c_str()), key3))
continue;
}
count++;
if (count < 200)
olist_show(obj, type, header);
header = 0;
}
if (count > 200)
{
sprintf(buf, "You have selected %d objects (too many to print all at once).\n",
count);
ch->send(buf);
//return;
}
else {
sprintf(buf, "You have selected %d objects.\n",
count);
ch->send(buf);
}
page_string(ch->desc, b_buf);
}

I took the advice to replace instances of ...
char buf[MAX_STRING_LENGTH] = {'\0'};
with ...
char buf[MAX_STRING_LENGTH]; *buf = 0;

Related

How to convert int type number/letter to char and *char?

I am using LittleFS library and ESP32 on arduino IDE.
I am reading a file using the example readFile function of LittleFS but I am trying to convert it for my needs.
The text written to the file is of this form:
LettersAndNumbersMax30&LettersAndNumbersMax30&00&00&01&01
Seperated by &. 2 text values of max 30 characters and 4 integers.
I want to build:
char *mytest1 containing the first text
char *mytest2 containing the second text
int mytest3 containing the first integer (2digits)
int mytest4 containing the second integer (2digits)
int mytest5 containing the third integer (2digits)
int mytest5 containing the forth integer (2digits)
file.read() returns and integer always. for example 38 for &.
void readFile(fs::FS &fs, const char * path){
Serial.printf("Reading file: %s\r\n", path);
File file = fs.open(path);
if(!file || file.isDirectory()){
Serial.println("- failed to open file for reading");
return;
}
Serial.println("- read from file:");
while(file.available()){
Serial.write(file.read());
}
file.close();
}
Its fairly straightforward. Test each byte read and act accordingly. Code below doesn't handle signs nor negative numbers. It also doesn't check if there are only digits for integers in the file.
#include ....
struct record_t
{
char myState1[31];
char myState2[31];
int myState3;
int myState4;
int myState5;
int myState6;
};
record_t record;
bool readFile(fs::FS &fs, const char * path);
void setup()
{
// ...
}
void loop()
{
//...
if (readFile(/*...*/))
{
Serial.printf("file reads OK\r\n");
//...
}
}
bool readFile(fs::FS &fs, const char * path)
{
Serial.printf("Reading file: %s\r\n", path);
File file = fs.open(path);
if (!file || file.isDirectory())
{
Serial.println("- failed to open file for reading");
return;
}
Serial.println("- read from file:");
int state = 0;
int index = 0;
// clear record.
record.myState1[0] = 0;
record.myState2[0] = 0;
record.myState3 = 0;
record.myState4 = 0;
record.myState5 = 0;
record.myState6 = 0;
bool valid = false;
for (int i = file.read(); i != -1; i = file.read())
{
char c = i & 0xFF;
Serial.write(c); // file.read() returns an int, that's why Serial.write()
// was printing numbers.
switch(state)
{
case 0:
if (index > sizeof(record.myState1) - 1) // avoid buffer overflow
index = sizeof(record.myState1) - 1;
if (c != '&')
{
record.myState1[index++] = c;
}
else
{
record.myState1[index] = 0;
++state;
index = 0;
}
break;
case 1:
if (index > sizeof(record.myState2) - 1) // avoid buffer overflow
index = sizeof(record.myState2) - 1;
if (c != '&')
{
record.myState2[index++] = c;
}
else
{
record.myState2[index] = 0;
++state;
index = 0;
}
break;
case 2:
if (c != '&')
record.myState3 = record.myState3 * 10 + (c - '0');
else
++state;
break;
case 3:
if (c != '&')
record.myState4 = record.myState4 * 10 + (c - '0');
else
++state;
break;
case 4:
if (c != '&')
record.myState5 = record.myState5 * 10 + (c - '0');
else
++state;
break;
case 5:
valid = true;
if (c != '&')
record.myState6 = record.myState6 * 10 + (c - '0');
else
++state;
break;
default: // reaching here is an error condition? You decide.
return false;
}
}
file.close();
if (!valid)
{
// clear record.
record.myState1[0] = 0;
record.myState2[0] = 0;
record.myState3 = 0;
record.myState4 = 0;
record.myState5 = 0;
record.myState6 = 0;
}
return valid;
}
file.read returns integer. So the integer is printed.
You to convert it to the string.
while(file.available()){
char s[2] = {0};
s[0] = file.read();
Serial.write(s);
}

Reference cannot be initialized/expression must have type class

I'm doing a quick binary tree program as a homework, but I am getting weird errors that I can't seem to figure out how to fix. Normally I'm programming in C#, and C is just slightly different but different enough for me to get confused.
Here is the code that is giving the error:
void SortArray() {//bubble sorting by float value of 'b'
int flag = 0;
do {
flag = 1;
for (int i = 0; i < arraySize - 1; i++)
{
if (stubList[i].b > stubList[i + 1].b) {
Swap(stubList[i], stubList[i + 1]);
flag = 0;
}
}
} while (flag == 0);
printf("Sorted by value of variable 'b'"); _getch(); _getch();
}
And here is the whole script:
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
using namespace std;
struct stub
{
char crown[51];//some custom name - can be empty
float b;//comparable value for tree sort
int c;//limited by maxint
stub *l;//left node(normally smaller "b" value than this node)
stub *r;//right node(normally bigger "b" value than this node)
};
stub *stubList[255];//empty list of a stub array with a safe casual amount
int arraySize = 0;
stub *head = NULL;//main stub(first)
stub *latest = NULL;//latest stub
stub *st = NULL;//used for creating and checking
FILE *fs = NULL;
char fileName[255];
int maxint = 20;//for var 'c'
void BTreeNodeToArray(stub *s) {
stubList[arraySize] = s;
arraySize++;
}
void Swap(stub &s1, stub &s2) {
stub temp = s2;
s1 = s2;
s2 = temp;
}
int MaxMin(int num) {
int clampedInt = num;
if (num < 0) clampedInt = 0;
else if (num > maxint) clampedInt = maxint;
return clampedInt;
}
//Create a completely new stub with crown, b, and c variables being filled here
void CreateElement() {
st = new stub;
printf("Adding information for node:\n");
printf("Node name: "); gets_s(st->crown);
printf("\n");
float f;
printf("Node float value (B): "); scanf_s("%f", &f);
st->b = f;
printf("\n");
int d;
printf("Node integer value (C): "); scanf_s("%d", &d);
st->c = d;
printf("\n");
st->c = MaxMin(st->c);
st->l = NULL;
st->r = NULL;
}
//creates the very first stub(root/head)
void CreateFirst() {
printf("First in tree. Adding root node...\n");
CreateElement();
head = st;
latest = head;
BTreeNodeToArray(head);
printf("Added head stub\ncrown: %s\nValue: %f\nExtra: %d", head->crown, head->b, head->c);
getchar();
getchar();
}
void AddStub() {
if (head == NULL) {
CreateFirst();
}
else {
CreateElement();//create newest node
latest = st;
st = head;
int depth = 0;
while (1) {
if ((latest->b <= st->b)) {//choose left if true
printf("Went left\n");
depth++;
if (st->l == NULL) {//node free, assign here
printf("Node assigned at depth %d\n", depth);
st->l = latest;
BTreeNodeToArray(latest);
getchar();
getchar();
break;
}
else {//loop again with next node
//printf("New loop (left)\n");
st = st->l;
}
}
else {//choose right
printf("Went right\n");
depth++;
if (st->r == NULL) {//node free, assign here
printf("Node assigned at depth %d\n", depth);
st->r = latest;
BTreeNodeToArray(latest);
getchar();
getchar();
break;
}
else {//loop again with next node
//printf("New loop (right)\n");
st = st->r;
}
}
}
}
}
void ViewArray() {
for (int i = 0; i < arraySize; i++)
{
printf_s("Node [%d]:\n\tCrown: %s\n\tweight: %f\n\tExta value(0 - %d): %d\n", i, stubList[i]->crown, stubList[i]->b, maxint, stubList[i]->c);
}
getchar();
}
void SortArray() {//bubble sorting by float value of 'b'
int flag = 0;
do {
flag = 1;
for (int i = 0; i < arraySize - 1; i++)
{
if (stubList[i].b > stubList[i + 1].b) {
Swap(stubList[i], stubList[i + 1]);
flag = 0;
}
}
} while (flag == 0);
printf("Sorted by value of variable 'b'"); _getch(); _getch();
}
void ProcessArray() {
char c = ' ';
int found = 0;
printf("Process with character: \n"); c = _getch();
if (arraySize <= 0) {
printf("No List!");
return;
}
char chkstr[5];
for (short i = 0; i < 5; i++)//simple assign to a 'string' 5 times
{
chkstr[i] = c;
}
for (int i = 0; i < arraySize; i++)
{
if (strstr(stubList[i]->crown, chkstr) != NULL) {
// contains
printf("B = %f at [%d] \n", stubList[i]->b, i);
found++;
}
}
if (found > 0) {
printf("---Found: %d with character %c---", found, c);
}
else {
printf("No elements found with '%c'", c);
}
getchar();
}
void ExportArray() {
FILE *fs = NULL;
char fileName[255];
errno_t err;
printf("Save to file as: \n"); gets_s(fileName);
if (strlen(fileName) == 0) {
printf("Failed to create file. File name empty!");
_getch();
_getch();
}
err = fopen_s(&fs, fileName, "wb");
if (err != 0) {
printf("Failed to create file!!!");
_getch();
_getch();
return;
}
for (int i = 0; i < arraySize; i++)
{
int written = fwrite(&stubList[i], sizeof(stub), 1, fs);
//fwrite(&gr[i], sizeof(student), 1, fs);
}
int numclosed = _fcloseall();
printf("Exported to file: %s", fileName);
getchar();
}
void CleanReset() {//reset all values and release memory (function used for import)
for (int i = 0; i < arraySize; i++)
{
delete stubList[i];
}
arraySize = 0;
st = NULL;
head = NULL;
latest = NULL;
}
void ImportArray() {
FILE *fs = NULL;
char fname[255];
errno_t err;
printf("Open FIle: "); gets_s(fname);
err = fopen_s(&fs, fname, "rb");
if (err == 0) {
CleanReset();
fseek(fs, 0, SEEK_END);
long size = ftell(fs);
arraySize = size / sizeof(stub);//get amount of students saved
fseek(fs, 0, SEEK_SET);
int i = 0;
st = new stub;
fread_s(&st, sizeof(stub), sizeof(stub), 1, fs);
stubList[i] = st;
while (!feof(fs)) {
i++;
st = new stub;
fread_s(&st, sizeof(stub), sizeof(stub), 1, fs);
stubList[i] = st;
}
printf("File data imported. Size: %d", arraySize);
getchar();
return;
}
printf("Failed to import file!!!");
getchar();
}
void main()
{
system("chcp 65001");//use utf8
char izb = 'i';
while (izb != '0') {
system("cls");
printf_s("1. Add stub\n");
printf_s("2. View Array\n");
printf_s("3. Sort Array\n");
printf_s("4. Process\n");
printf_s("5. Export array to file\n");
printf_s("6. Import array from file\n");
printf_s("0. Exit\n\n");
printf_s("Choose action:\n"); izb = _getch();
switch (izb)
{
case '1':
AddStub();
break;
case '2':
ViewArray();
break;
case '3':
SortArray();
break;
case '4':
ProcessArray();
break;
case '5':
ExportArray();
break;
case '6':
ImportArray();
break;
case '0':
//Exit();
break;
}
}
}
The error is that you want to pass a stub * to a function that wants a stub &. The first one is a pointer, the second one is a reference.
You have two options.
First option (imho recommended):
Change your swap function to accept pointers instead of references.
void Swap(stub *s1, stub *s2) {
stub temp = *s2;
*s1 = *s2;
*s2 = temp;
}
Second option:
Dereference the parameters before passing to swap:
Swap(*(stubList[i]), *(stubList[i + 1]));
You have to undestand that the datatype in your list is a pointer to stub, the function Swap wants a reference, which are different things in C++.
For a better understanding I recommend reading this: https://www.geeksforgeeks.org/pointers-vs-references-cpp/

Error in Xcode: Thread 1: EXC_BAD_ACCESS (code=1, address=0xe8)

This is supposed to be a c++ game which works by reading in files. How ever, I am not really sure what is the problem in the code below. When I enter the file name it gives me this error (code is below, problematic line is also shown). If you can't fix it can you at least tell me why this seems to work fine in another computer, but when I try to compile in Xcode it goes wrong?
#include "AdvRoom.h"
AdvRoom::AdvRoom()
{
}
bool AdvRoom::readRoom(ifstream &roomFile)
{
bool success = true;
char data[64];
int pointer;
while ((roomFile.get(data[0])) && data[0] == '\n') {}
roomFile.unget();
if (success && !roomFile.eof() && roomFile.good()) {
roomFile.get(data, 64);
this->number = atoi(data);
roomFile.get(data[0]);
}
else success = false;
if (success && !roomFile.eof() && roomFile.good()) {
roomFile.get(data, 64);
this->name = data;
roomFile.get(data[0]);
}
else success = false;
if (success && !roomFile.eof() && roomFile.good()) {
roomFile.get(data, 64);
while (data[0] != '-' && success) {
this->description.push_back(data);
if (success && !roomFile.eof() && roomFile.good()) {
roomFile.get(data[0]);
roomFile.get(data, 64);
}
else success = false;
}
roomFile.get(data[0]);
}
else success = false;
if (success && !roomFile.eof() && roomFile.good()) {
// Check for \n
string direction;
int destination = 0;
string key;
while (roomFile.peek() != '\n' && success) {
if (success && !roomFile.eof() && roomFile.good()) {
roomFile.get(data, 64, ' ');
direction = data;
while ((roomFile.get(data[0])) && data[0] == ' ') {}
roomFile.unget();
int i = 0;
while ((roomFile.get(data[i])) && data[i] != '\n' && data[i] != ' ') {
++i;
}
if (data[i] == ' ') {
data[i] = '\0';
destination = atoi(data);
roomFile.get(data, 64, '\n');
key = data;
roomFile.get(data[0]);
}
else if (data[i] == '\n') {
data[i] = '\0';
destination = atoi(data);
key = "";
//roomFile.get(data[0]);
}
AdvMotionTableEntry entry(direction, destination, key);
this->motionTable.push_back(entry);
}
else success = false;
}
}
else success = false;
return success;
}
vector<string> AdvRoom::getDescription()
{
vector<string> copyDesc = this->description;
return copyDesc;
}
string AdvRoom::getName()
{
string copyName = this->name;
return copyName;
}
void AdvRoom::addObject(AdvObject obj)
{
// This function should add the obj to the room.
// It however, should not add the object to the room
// if the room already contains the object.
this->objects.push_back(obj);
}
AdvObject AdvRoom::removeObject(string objName)
{
AdvObject deletedObj;
// This function should remove the object with objName.
for (int i = 0; i < this->objects.size(); ++i) {
if (this->objects[i].getName() == objName) {
deletedObj = this->objects[i];
this->objects.erase(this->objects.begin() + i);
}
}
return deletedObj;
}
bool AdvRoom::containsObject(string objName)
{
// Returns true if object with objName is in the room.
bool success = false;
for (int i = 0; i < this->objects.size(); ++i) {
if (this->objects[i].getName() == objName) {
success = true;
}
}
return success;
}
int AdvRoom::objectCount()
{
return this->objects.size();
}
AdvObject AdvRoom::getObject(int index)
{
return this->objects.at(index);
}
bool AdvRoom::hasBeenVisited()
{
bool truth = this->isVisited;
return truth;
}
void AdvRoom::setVisited(bool flag)
{
this->isVisited = flag;
}
vector<AdvMotionTableEntry> AdvRoom::getMotionTable()
{
vector<AdvMotionTableEntry> copyMotionTable = this->motionTable;
return copyMotionTable;
}
int AdvRoom::getRoomNumber()
{
int copyNumber = this->number;
return copyNumber;
}

batch processing in a simple shell

Hey folks I am making a batch command function in a shell that reads from a txt file and pipes it to a child to exec.
I'm having an issue with exec. I suspect it is something with the null terminator. If I execl with an L and an explicit (char*)NULL the exec runs. If I execvp(argIn[0],argIn) nothing runs and returns a -1. If I execvp with an explicit (char*)NULL I get an error cannot convert char* to char* constant*. I read somewhere that it might be the g++ compiler giving me the error but the gcc compiler wouldn't give the error. Right now it won't compile with gcc though so I'm not sure if that's true. But it shouldn't need the explicit terminator anyway. I'm not sure if the '\0' I have stored is being passed to the exec right. It checks out when I pass it to other functions though so maybe that's not the solution.
Second, my for loop won't exec more than once which I think is more to do with the first solution. I can get the execl to fork with an index but I can't increment the index to point to the right token the next time through because the child should be wiping out my index right?
Anyway it's been 3 weeks of digging to figure out what's wrong. I failed the assignment. Probably going to fail the class. I don't know what else to try. So any help I would appreciate.
My question is why would the exec function not execute the program? I'm passing execvp(program name, program name, option, option, '\0') and not getting a result.
or
execl(program name, program name[index], option[index+1], option[index+1], (char*)NULL) and getting a result. They both seem to be following the parameters but only one is giving me a result.
#include<string.h>
#include<iostream>
#include<ctype.h>
#include<stdlib.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
using namespace std;
int makearg(char s[], char**args[]);
int main(int argc, char *argv[])
{
char **argIn;
int argCount;
int pos = 0;
char str[500];
pid_t pid = fork();
for(int i = 0; i < 4; i++)
{
if(pid == 0)
{
while(fgets(str, 500, stdin) != NULL)
{
cout << "String loaded: " << str;
argCount = makearg(str, &argIn);
execvp(argIn[0],argIn); //nothing exec
// execl(argIn[0],argIn[0],argIn[1],argIn[2],(char*)NULL); //exec but requires index.
else if(pid < 0)
{
perror("fork() error");
exit(-1);
}
else if(pid > 0)
{
cout << "Parent waiting" << endl;
wait(NULL);
}
}
return 0;
}
int makearg(char s[], char**args[])
{
int counter = 1;
int tokenLen = 1;
int i = 0;
int j = 0;
int k = 0;
char arg1[50];
char * arg2;
strcpy(arg1, s);
//Count white space.
while (arg1[j] != '\0')
{
if (arg1[j] == ' ' || arg1[j] == '\0' || arg1[j] == '\n')
{
counter++;
}
j++;
}
//Allocate the number of rows to be pointed to.
args[0] = (char**) malloc(counter + 1);
if(args[0] == NULL)
exit(1);
//Allocate the size of the c string arrays
j = 0;
while(arg1[j] != '\0')
{
if (arg1[j] == ' ' || arg1[j] == '\0' || arg1[j] == '\n')
{
(*args)[i] = (char*)(malloc(tokenLen));
if((*args)[i] == NULL)
exit(1);
tokenLen = 0;
i++;
}
j++;
tokenLen++;
}
(*args)[i] = (char*)(malloc(tokenLen));
if ((*args)[i] == NULL)
exit(1);
//reset values
i = 0;
j = 0;
//Set arg2 to point to args row head. Transfer values from arg1 to arg2.
arg2 = ((*args)[i]);
while(arg1[j] != '\0')
{
if (arg1[j] != ' ' && arg1[j] != '\0' && arg1[j] != '\n')
{
arg2[k] = arg1[j];
k++;
}
else
{
arg2[k] = '\0';
i++;
k = 0;
arg2 = ((*args)[i]);
}
j++;
}
arg2[k] = '\0';
if (counter < 1)
{
return -1;
}
return counter;
}
I took your posted code, updated it to fix build errors and ran. I executed the simple command "ls" but I got the message
String loaded: ls
ls: cannot access '': No such file or directory
That indicated to me that makearg is not working correctly. Then, I added a function to help with diagnosing the problem.
void printArguments(char **args)
{
for ( int j = 0; args[j] != NULL; ++j )
{
printf("args[%d]: %s\n", j, args[j]);
}
}
and added a call to it from main, right after the call to makearg.
argCount = makearg(str, &argIn);
printArguments(argIn);
I got the output:
String loaded: ls
args[0]: ls
args[1]:
ls: cannot access '': No such file or directory
That indicated to me that makearg was not dealing with the end of the line correctly. It creates an empty argument.
I added couple of functions to trim whitespaces from the left and from the right. After that, the child process was able to execute "ls" correctly.
Here's the updated program.
#include<string.h>
#include<iostream>
#include<ctype.h>
#include<stdlib.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
using namespace std;
int makearg(char s[], char**args[]);
void printArguments(char **args)
{
for ( int j = 0; args[j] != NULL; ++j )
{
printf("args[%d]: %s\n", j, args[j]);
}
}
int main(int argc, char *argv[])
{
char **argIn;
int argCount;
char str[500];
pid_t pid = fork();
for(int i = 0; i < 4; i++)
{
if(pid == 0)
{
while(fgets(str, 500, stdin) != NULL)
{
cout << "String loaded: " << str;
argCount = makearg(str, &argIn);
printArguments(argIn);
execvp(argIn[0],argIn); //nothing exec
}
}
else if(pid < 0)
{
perror("fork() error");
exit(-1);
}
else if(pid > 0)
{
cout << "Parent waiting" << endl;
wait(NULL);
}
}
return 0;
}
void trimWhiteSpacesLeft(char s[])
{
int i = 0;
for ( ; isspace(s[i]); ++i );
if ( i == 0 )
{
return;
}
int j = 0;
for (; s[i] != '\0'; ++j, ++i )
{
s[j] = s[i];
}
s[j] = '\0';
}
void trimWhiteSpacesRight(char s[])
{
int len = strlen(s);
int i = len-1;
for ( ; i >= 0; --i )
{
if ( !isspace(s[i]) )
{
break;
}
}
s[i+1] = '\0';
}
int makearg(char s[], char**args[])
{
int counter = 1;
int tokenLen = 1;
int i = 0;
int j = 0;
int k = 0;
char arg1[50];
char * arg2;
strcpy(arg1, s);
// Trim whitespaces from both ends.
trimWhiteSpacesLeft(arg1);
trimWhiteSpacesRight(arg1);
//Count white space.
while (arg1[j] != '\0')
{
if (arg1[j] == ' ' || arg1[j] == '\0' )
{
counter++;
}
j++;
}
//Allocate the number of rows to be pointed to.
args[0] = (char**) malloc(counter + 1);
if(args[0] == NULL)
exit(1);
//Allocate the size of the c string arrays
j = 0;
while(arg1[j] != '\0')
{
if (arg1[j] == ' ' || arg1[j] == '\0' || arg1[j] == '\n')
{
(*args)[i] = (char*)(malloc(tokenLen));
if((*args)[i] == NULL)
exit(1);
tokenLen = 0;
i++;
}
j++;
tokenLen++;
}
(*args)[i] = (char*)(malloc(tokenLen));
if ((*args)[i] == NULL)
exit(1);
//reset values
i = 0;
j = 0;
//Set arg2 to point to args row head. Transfer values from arg1 to arg2.
arg2 = ((*args)[i]);
while(arg1[j] != '\0')
{
if (arg1[j] != ' ' && arg1[j] != '\0' && arg1[j] != '\n')
{
arg2[k] = arg1[j];
k++;
}
else
{
arg2[k] = '\0';
i++;
k = 0;
arg2 = ((*args)[i]);
}
j++;
}
arg2[k] = '\0';
if (counter < 1)
{
return -1;
}
return counter;
}

How to get Serial Port profile SDP record for remote device

I am trying to write an application that pairs a remote bluetooth device with Windows Mobile/CE handheld and get the service of the device.
I noticed that when you manually pair a device and set the service through the system(eg. go to settings->Bluetooth-> add device) it generates an sdprecord value in the following registry
HKLM/Software/Microsoft/Bluetooth/Device/{deviceAddress}/{*Service_UUID*}.
I am basically trying to implement this in my program.
I followed the following documentations:
http://msdn.microsoft.com/en-us/library/ms883458.aspx
http://msdn.microsoft.com/en-us/library/ms883398.aspx
and then convert the SDPrecord into binary and write it to the registry:
RegSetValueEx(hSerialPortKey,_T("sdprecord"),0,REG_BINARY,(BYTE*)&pRecord,sizeof(pRecord)*2+1);
The result is not the same as what I would get when I manually pair the device.
What am I doing wrong? How can I retrieve the SDP record? Thank you in advance.
Below is my code
BTHNS_RESTRICTIONBLOB RBlob;
memset(&RBlob,0,sizeof(BTHNS_RESTRICTIONBLOB));
RBlob.type = SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST;
RBlob.numRange = 1;
RBlob.uuids[0].uuidType= SDP_ST_UUID16;//SDP_ST_UUID128;
RBlob.uuids[0].u.uuid16= SerialPortServiceClassID_UUID16;
RBlob.pRange[0].minAttribute =SDP_ATTRIB_PROTOCOL_DESCRIPTOR_LIST;
RBlob.pRange[0].maxAttribute = SDP_ATTRIB_PROTOCOL_DESCRIPTOR_LIST;
SOCKADDR_BTH sa;
memset (&sa, 0, sizeof(SOCKADDR_BTH));
BTH_ADDR *pDeviceAddr = &devAddress;
*(BTH_ADDR *)(&sa.btAddr) = *pDeviceAddr;
sa.addressFamily = AF_BTH;
CSADDR_INFO csai;
memset(&csai,0,sizeof(CSADDR_INFO));
csai.RemoteAddr.lpSockaddr = (sockaddr*)&sa;
csai.RemoteAddr.iSockaddrLength = sizeof(sa);
BLOB blob;
blob.cbSize = sizeof(BTHNS_RESTRICTIONBLOB);
blob.pBlobData = (BYTE *)&RBlob;
WSAQUERYSET wsaq;
memset(&wsaq,0,sizeof(WSAQUERYSET));
wsaq.dwSize = sizeof(WSAQUERYSET);
wsaq.dwNumberOfCsAddrs = 1;
wsaq.dwNameSpace = NS_BTH;
wsaq.lpBlob = &blob;
wsaq.lpcsaBuffer = &csai;
wsaq.lpServiceClassId = &serialPortUUID;
//Initialising winsock
WSADATA data;
int result = WSAStartup(MAKEWORD(2, 2), &data);//initializing winsock
if (hLib == NULL)
{
return S_FALSE;
}
result = WSALookupServiceBegin (&wsaq,0, &hLookup);
while (result ==ERROR_SUCCESS )
{
BYTE sdpBuffer[4096];
memset(sdpBuffer,0,sizeof(sdpBuffer));
LPWSAQUERYSET pResult = (LPWSAQUERYSET)&sdpBuffer;
dwSize = sizeof(sdpBuffer);
pResult->dwSize = sizeof(WSAQUERYSET);
pResult->dwNameSpace = NS_BTH;
pResult->lpBlob = NULL;
pResult->lpServiceClassId = &serialPortUUID;
result = WSALookupServiceNext(hLookup,0,&dwSize,pResult);
if(result == -1 )
{
int error;
error = WSAGetLastError();
if (error == WSA_E_NO_MORE)
break;
}
else
{
//Get SDP record
if (pResult != NULL)
{
if (ERROR_SUCCESS != ServiceAndAttributeSearchParse(pResult->lpBlob->pBlobData,pResult->lpBlob->cbSize,&pRecordArg,&ulRecords)) { //error handling}
ULONG recordIndex;
for (recordIndex = 0; recordIndex < ulRecords; recordIndex++) {
pRecord = pRecordArg[recordIndex];}
I think the code should be ok.Here's my code
int FindRFCOMMChannel (unsigned char *pStream, int cStream, unsigned char *pChann)
{
ISdpRecord **pRecordArg;
int cRecordArg = 0;
*pChann = 0;
int hr = ServiceAndAttributeSearch(pStream, cStream, &pRecordArg, (ULONG *)&cRecordArg);
if (hr != ERROR_SUCCESS)
{
BT_ERROR( CBTRFCOMMMgr, PerformServiceSearch, "ServiceAndAttributeSearch ERROR %d\n");
return hr;
}
for (int i = 0; (! *pChann) && (i < cRecordArg); i++)
{
ISdpRecord *pRecord = pRecordArg[i]; // particular record to examine in this loop
CNodeDataFreeString protocolList; // contains SDP_ATTRIB_PROTOCOL_DESCRIPTOR_LIST data, if available
if (ERROR_SUCCESS != pRecord->GetAttribute(SDP_ATTRIB_PROTOCOL_DESCRIPTOR_LIST,&protocolList) ||
(protocolList.type != SDP_TYPE_CONTAINER))
continue;
ISdpNodeContainer *pRecordContainer = protocolList.u.container;
int cProtocols = 0;
NodeData protocolDescriptor; // information about a specific protocol (i.e. L2CAP, RFCOMM, ...)
pRecordContainer->GetNodeCount((DWORD *)&cProtocols);
for (int j = 0; (! *pChann) && (j < cProtocols); j++) {
pRecordContainer->GetNode(j,&protocolDescriptor);
if (protocolDescriptor.type != SDP_TYPE_CONTAINER)
continue;
ISdpNodeContainer *pProtocolContainer = protocolDescriptor.u.container;
int cProtocolAtoms = 0;
pProtocolContainer->GetNodeCount((DWORD *)&cProtocolAtoms);
for (int k = 0; (! *pChann) && (k < cProtocolAtoms); k++) {
NodeData nodeAtom; // individual data element, such as what protocol this is or RFCOMM channel id.
pProtocolContainer->GetNode(k,&nodeAtom);
if (IsRfcommUuid(&nodeAtom)) {
if (k+1 == cProtocolAtoms) {
// misformatted response. Channel ID should follow RFCOMM uuid
break;
}
NodeData channelID;
pProtocolContainer->GetNode(k+1,&channelID);
*pChann = (unsigned char)GetChannel(&channelID);
break; // formatting error
}
}
}
}
for (i = 0; i < cRecordArg; i++)
pRecordArg[i]->Release();
CoTaskMemFree(pRecordArg);
return (*pChann != 0) ? 1:0;
}
int IsRfcommUuid(NodeData *pNode) {
if (pNode->type != SDP_TYPE_UUID)
return FALSE;
if (pNode->specificType == SDP_ST_UUID16)
return (pNode->u.uuid16 == RFCOMM_PROTOCOL_UUID16);
else if (pNode->specificType == SDP_ST_UUID32)
return (pNode->u.uuid32 == RFCOMM_PROTOCOL_UUID16);
else if (pNode->specificType == SDP_ST_UUID128)
return (0 == memcmp(&RFCOMM_PROTOCOL_UUID,&pNode->u.uuid128,sizeof(GUID)));
return FALSE;
}
int GetChannel (NodeData *pChannelNode) {
if (pChannelNode->specificType == SDP_ST_UINT8)
return pChannelNode->u.uint8;
else if (pChannelNode->specificType == SDP_ST_INT8)
return pChannelNode->u.int8;
else if (pChannelNode->specificType == SDP_ST_UINT16)
return pChannelNode->u.uint16;
else if (pChannelNode->specificType == SDP_ST_INT16)
return pChannelNode->u.int16;
else if (pChannelNode->specificType == SDP_ST_UINT32)
return pChannelNode->u.uint32;
else if (pChannelNode->specificType == SDP_ST_INT32)
return pChannelNode->u.int32;
return 0;
}