I'm currently trying to make some sort of "aliaslist" for a game.
I've gotten so far where a user connects, the code check if their "aliaslist" file exist, it it doesn't it'll create one.
Once its created, their playername gets saved to that file, However, if they reconnect it will be namename
I want to achieve it to have a name on each line like:
name
name
I currently have this code, and was wondering what I am doing wrong. Note, its the q3engine.
if(!isBot) {
file = va("aliaslist/%s", onlyip);
trap_FS_FOpenFile( file, &f, FS_APPEND_TEXT );
if ( !f ) {
trap_FS_FOpenFile( file, &f, FS_WRITE_TEXT );
}
else {
int len;
len = strlen(client->pers.netname);
trap_FS_Write(va("%s \n", client->pers.netname), len, f);
trap_FS_FCloseFile( f );
}
}
You only write strlen(client->pers.netname) number of characters to the file in your trap_FS_Write.
To write the space and the newline as well:
trap_FS_Write(va("%s \n", client->pers.netname), len + 2, f);
(Notice the + 2)
Related
In my file let's assume it has the following content:
my_file.txt
/* My file "\n". */
Hello World
If I wanted generate a file and pass this same content as a string in C code, the new file would look like this:
my_generated_c_file.c
const char my_file_as_string[] = "/* My file \"\\n\". */\nHello World\n\n";
In an unfortunate attempt, I tried to simply add the chars one by one:
#include <stdio.h>
int main ()
{
FILE *fp_in = fopen("my_file.txt", "r");
FILE *fp_out = fopen("my_generated_c_file.c", "w");
fseek(fp_in, 0L, SEEK_END);
long size = ftell(fp_in);
fseek(fp_in, 0L, SEEK_SET);
fprintf(fp_out, "const char my_file_as_string[] = \"");
while (size--) {
fprintf(fp_out, "%c", getc(fp_in));
}
fprintf(fp_out, \";\n\n");
fclose(fp_in);
fclose(fp_out);
return 0;
}
But that doesn't work because a '\n' for example is read as a line break and not "\\n".
How to solve this?
You could simply print a '\\' wherever a '\' was present in the original file:
while (size--) {
char next_c = getc(fp_in);
if(next_c == '\\') {
fputs("\\\\", fp_out);
}
else {
fputc(next_c, fp_out);
}
}
You'll probably also want to perform other such transformations as well, such as replacing line breaks with \n.
I have a directory trial which contains hundreds of histograms in it and a macro. Each is called in a way hists09876_blinded.root or hists12365_blinded.root. The order, however, is not like that. There are some missig histograms like hists10467_blinded.root hists10468_blinded.root hists10470_blinded.root. The ultimate goal is to get one histogram on a canvas which represents all of those combined together. The tricky thing is that each hists*****_blinded.root has around 15 1D histos in it, I need to pull out just one from each called sc*****.
I have 2 ideas, but I guess I should combine them together to get the final result.
First idea was to open histo by histo, but since there are some missed histos in the order, that does not work well.
void overlap()
{
TCanvas *time = new TCanvas("c1", "overlap", 0, 0, 800, 600);
const char* histoname = "sc";
const int NFiles = 256;
for (int fileNumber = 09675; fileNumber < NFiles; fileNumber++)
{
TFile* myFile = TFile::Open(Form("hists%i_blinded.root", fileNumber));
if (!myFile)
{
printf("Nope, no such file!\n");
return;
}
TH1* h1 = (TH1*)myFile->Get(histoname);
if (!h1)
{
printf("Nope, no such histogram!\n");
return;
}
h1->SetDirectory(gROOT);
h1->Draw("same");
myFile->Close();
}
}
After having read multiple posts on the pretty much the same question (1, 2, and this one) I have figured out what was wrong with my answer here: I did not know the file name may contain a zero if the number in its name is < 10000. Also, I failed to understand that the asterisks in the histogram name, which you refer to as sc*****, actually hide the same number as in the file name! I thought this was something completely different. So in that case I suggest you construct the file name and the histogram name you should be after in the same loop:
void overlap_v2()
{
TCanvas *time = new TCanvas("c1", "overlap", 0, 0, 800, 600);
const int firstNumber = 9675;
const int NFiles = 100000;
for (int fileNumber = firstNumber; fileNumber < firstNumber+NFiles; fileNumber++)
{
const char* filename = Form("trial/hists%05i_blinded.root", fileNumber);
TFile* myFile = TFile::Open(filename);
if (!myFile)
{
printf("Can not find a file named \"%s\"!\n", filename);
continue;
}
const char* histoname = Form("sc%05i", fileNumber);
TH1* h1 = (TH1*)myFile->Get(histoname);
if (!h1)
{
printf("Can not find a histogram named \"%s\" in the file named \"%s\"!\n", histoname, filename);
continue;
}
h1->SetDirectory(gROOT);
h1->Draw("same");
myFile->Close();
}
}
Since it is expected that some files are "missing", I suggest not to try to guess the names of the files that actually exist. Instead, use a function that lists all files in a given directory and from that list filter out those files that match the pattern of files you want to read. See for example these links for how to read the content of a directory in C++:
How can I get the list of files in a directory using C or C++?
http://www.martinbroadhurst.com/list-the-files-in-a-directory-in-c.html
I am using ifstream to open a file and read line by line and print to console.
Now, I also want to make sure that if the file gets updated, it reflects. My code should handle that.
I tried setting fseek to end of the file and then looking for new entries by using peek. However, that did not work.
Here's some code I used
bool ifRead = true;
while (1)
{
if (ifRead)
{
if (!file2read.eof())
{
//valid file. not end of file.
while (getline(file2read, line))
printf("Line: %s \n", line.c_str());
}
else
{
file2read.seekg(0, file2read.end);
ifRead = false;
}
}
else
{
//I thought this would check if new content is added.
//in which case, "peek" will return a non-EOF value. else it will always be EOF.
if (file2read.peek() != EOF)
ifRead = true;
}
}
}
Any suggestions on what could be wrong or how I could do this.
Im working on an online game and I have a problem with getting the ms-sql results into a other cpp file.
cpp file1 to start the query:
databaseManager.Query( hDB, new CQuery_AuthServer(req->awchUserId, req->awchPasswd);
req->awchUserId and req->awchPasswd are data from socket (username and password)
now on cpp file2 I execute the query inside a class
class CQuery_AuthServer : public CNtlQuery
{
public:
CQuery_AuthServer(const WCHAR * lpszUserID, const WCHAR * lpszUserPW)
{
ZeroMemory( m_szUserID, MAX_SIZE_USER_ID + 1 );
ZeroMemory( m_szUserPW, MAX_SIZE_USER_PW + 1 );
memcpy(m_szUserID, lpszUserID, MAX_SIZE_USER_ID);
memcpy(m_szUserPW, lpszUserPW, MAX_SIZE_USER_PW);
}
int ExecuteQuery(CNtlDatabaseConnection * pConnection)
{
FIND_SQLUNIT( SP_AuthLogin, pConnection, pSqlUnit2 );
if( NULL == pSqlUnit2 )
{
return NTL_FAIL;
}
strncpy_s( pSqlUnit2->m_szUserID, m_szUserID, MAX_SIZE_USER_ID );
strncpy_s( pSqlUnit2->m_szUserPW, m_szUserPW, MAX_SIZE_USER_ID );
pSqlUnit2->Exec();
printf("ExecuteQuery Done: result: %i ACC ID: %i \n", pSqlUnit2->m_nResultCode, pSqlUnit2->m_dwAccountID );
return NTL_SUCCESS;
}
public:
char m_szUserID[MAX_SIZE_USER_ID + 1];
char m_szUserPW[MAX_SIZE_USER_PW + 1];
};
This is needed for the query
BEGIN_DECLARE_SQLUNIT( SP_AuthLogin, "{ ? = call AuthLogin(?,?,?) }" )
BEGIN_VARIABLE()
char m_szUserID[MAX_SIZE_USER_ID + 1];
char m_szUserPW[MAX_SIZE_USER_PW + 1];
int m_dwAccountID;
int m_nResultCode;
END_VARIABLE()
BEGIN_PARAM(3)
PARAM_ENTRY(SQL_PARAM_OUTPUT, m_nResultCode)
PARAM_ENTRY_STR(SQL_PARAM_INPUT, m_szUserID)
PARAM_ENTRY_STR(SQL_PARAM_INPUT, m_szUserPW)
PARAM_ENTRY(SQL_PARAM_OUTPUT, m_dwAccountID)
END_PARAM()
END_DECLARE_SQLUNIT()
Now I can get the result but the result only works inside int ExecuteQuery
The query results are:
pSqlUnit2->m_nResultCode
pSqlUnit2->m_dwAccountID
how can I get those 2 results in the first cpp file where I made the query?
edit: the first cpp file:
void CClientSession::SendCharLogInReq(CNtlPacket * pPacket)
{
sUA_LOGIN_REQ * req = (sUA_LOGIN_REQ *)pPacket->GetPacketData();
HDATABASE hDB = INVALID_HDATABASE;
CNtlDatabaseManager databaseManager;
databaseManager.Query( hDB, new CQuery_AuthServer(req->awchUserId, req->awchPasswd) );
//WANT RESULT HERE
}
I dont really know what to do.. Im really newbie
here is the complete source https://www.sendspace.com/file/oc5v34
at PacketAuthServer.cpp I run the query
at AuthQueryServer.h I execute the query
Disregard the previous answer. The problem with the previous answer is that it was expecting databaseManager.Query to be syncrhonous, and to execute CQuery_AuthServer::ExecuteQuery before it returns to the caller. In fact it doesn't - it just adds the query to the queue, and your database management framework doesn't give you the ability to wait for completion of that query.
You should read the NtlDatabase manual to know how to make synchronous database calls
I'm sorry, it would be extremely difficult to make a fully reproducible version of the error --- so please bare with my schematic code.
This program retrieves information from a web page, processes it, and saves output to an ASCII file. I also have a 'log' file (FILE *theLog---contained within a Manager object) for reporting errors, etc.
Some background methods:
// Prints string to log file
void Manager::logEntry(const string lstr) {
if( theLog != NULL ) { fprintf(theLog, "%s", lstr.c_str()); }
}
// Checks if file with given name already exists
bool fileExists(const string fname) {
FILE *temp;
if( temp = fopen(fname.c_str(), "r") ) {
fclose(temp);
return true;
} else { return false; }
}
// Initialize file for writing (some components omitted)...
bool initFile(FILE *&oFile, const string fname) {
if(oFile = fopen(fname.c_str(), "w") ) { return true; }
else { return false; }
}
The stuff causing trouble:
// Gets data from URL, saves to file 'dataFileName', input control flag 'foreCon'
// stu is some object that has string which i want
bool saveData(Manager *man, Stuff *stu, string dataFileName, const int foreCon) {
char logStr[CHARLIMIT_LARGE]; // CHARLIMIT_LARGE = 2048
sprintf(logStr, "Saving Data...\n");
man->logEntry( string(logStr) ); // This appears fine in 'theLog' correctly
string data = stu->getDataPrefixStr() + getDataFromURL() + "\n"; // fills 'data' with stuff
data += stu->getDataSuffixStr();
if( fileExists(dataFileName) ) {
sprintf(logStr, "save file '%s' already exists.", dataFileName.c_str() );
man->logEntry( string(logStr) );
if( foreCon == -1 ) {
sprintf(logStr, "foreCon = %d, ... exiting.", foreCon); // LINE 'A' : THIS LINE ENDS UP IN OUTPUT FILE
tCase->logEntry( string(logStr) );
return false;
} else {
sprintf(logStr, "foreCon = %d, overwriting file.", foreCon); // LINE 'B' : THIS LINE ENDS UP IN LOG FILE
tCase->logEntry( string(logStr) );
}
}
// Initialize output file
FILE *outFile;
if( !initFile(outFile, dataFileName) ) {
sprintf(logStr, "couldn't initFile '%s'", dataFileName.c_str());
tCase->logEntry( string(logStr) );
return false;
}
fprintf(outFile, "%s", data.c_str()); // print data to output file
if( fclose(outFile) != EOF) {
sprintf(logStr, "saved to '%s'", dataFileName.c_str());
tCase->logEntry( string(logStr) );
return true;
}
return false;
}
If the file already exists, AND 'int foreCon = -1' then the code should print out line 'A' to the logFile. If the file exists and foreCon != -1, the old file is overwritten with data. If the file doesn't exist, it is created, and the data is written to it.
The result however, is that a broken up version of line 'A' appears in the data file AND line 'B' is printed in the log file!!!!
What the data file looks like:
.. exiting.20130127 161456
20130127 000000,55,17,11,0.00
20130127 010000,54,17,11,0.00
... ...
The second line and onward look correct, but there is an extra line that contains part of line 'A'.
Now, the REALLY WEIRD PART. If I comment out everything in the if( foreCon == -1) { ... } block, then the data file looks like:
%d, ... exiting.20130127 161456
20130127 000000,55,17,11,0.00
20130127 010000,54,17,11,0.00
... ...
There is still an extra line, but it is the LITERAL CODE copied into the data file.
I think there is a poltergeist in my code. I don't understand how any of this could happen.
Edit: I've tried printing to console the data string, and it gives the same messed up values: i.e. %d, ... exiting.20130127 161456 - so it must be something about the string instead of the FILE *
Answer based on your latest comment:
getDataPrefixStr() ends up returning a string which starts with
something like string retStr = COMCHAR + " file created on ..."; such
that const char COMCHAR = '#';. Could the COMCHAR be the problem??
You can't add characters and string literals (which are arrays of char, not strings) like that.
You're adding 35 (the ASCII for "#") to the address of " file created on ... ", i.e. getDataPrefixStr() is whatever starts 35 characters from the start of that string. Since all literal strings are stored together in the same data area, you'll get strings from the program in the output.
Instead, you cold do
const string COMCHAR = "*";
string retStr = COMCHAR + " file created on ...";
It could be that logStr is too short and that it is causing data to be overwritten in other buffers (did you double check CHARLIMIT_LARGE?). You can diagnose this by commenting all writes to logStr (sprintf) and see if data is still corrupted. In general, your code is vulnerable to this if a user can set dataFileName (to be a very long string); use snprintf or ostringstream instead.
Otherwise, I would guess that either stu->getDataPrefixStr() or getDataFromURL() are returning corrupted results or return type char* instead of string. Try printing these values to the console directly to see if they are corrupted or not. If they return a char*, then data = stu->getDataPrefixStr() + getDataFromURL() will have undefined behavior.
if( temp = fopen(fname.c_str(), 'r') ) {
should be
if( temp = fopen(fname.c_str(), "r") ) {