How to get mode name using XCB? - x11

In Xlib the structure XRRModeInfo contains, aside from nameLength field, the name itself. But in XCB the corresponding structure xcb_randr_mode_info_t only contains name_len, and there seems to be no function to get actual name string.
I do see all the mode names in the string returned by xcb_randr_get_screen_resources_names(), but they are all concatenated, and I don't know how to find the offset of a particular mode in this string.
So, how can I get the mode name using XCB?

I do see all the mode names in the string returned by xcb_randr_get_screen_resources_names(), but they are all concatenated, and I don't know how to find the offset of a particular mode in this string.
You have the length of the individual names and you know the length of each name, so you just have to count bytes:
#include <stdio.h>
#include <xcb/randr.h>
int main()
{
xcb_connection_t *c = xcb_connect(NULL, NULL);
xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(c)).data;
// TODO: Error handling
// TODO: Checking if the RandR extension is available
xcb_randr_get_screen_resources_reply_t *reply =
xcb_randr_get_screen_resources_reply(c,
xcb_randr_get_screen_resources(c, screen->root),
NULL);
xcb_randr_mode_info_iterator_t iter = xcb_randr_get_screen_resources_modes_iterator(reply);
uint8_t *names = xcb_randr_get_screen_resources_names(reply);
while (iter.rem) {
xcb_randr_mode_info_t *mode = iter.data;
printf("Mode %d has size %dx%d and name %.*s\n",
mode->id, mode->width, mode->height, mode->name_len, names);
names += mode->name_len;
xcb_randr_mode_info_next(&iter);
}
free(reply);
xcb_disconnect(c);
return 0;
}

Related

Extract trailing int from string containing other characters

I have a problem in regards of extracting signed int from string in c++.
Assuming that i have a string of images1234, how can i extract the 1234 from the string without knowing the position of the last non numeric character in C++.
FYI, i have try stringstream as well as lexical_cast as suggested by others through the post but stringstream returns 0 while lexical_cast stopped working.
int main()
{
string virtuallive("Images1234");
//stringstream output(virtuallive.c_str());
//int i = stoi(virtuallive);
//stringstream output(virtuallive);
int i;
i = boost::lexical_cast<int>(virtuallive.c_str());
//output >> i;
cout << i << endl;
return 0;
}
How can i extract the 1234 from the string without knowing the position of the last non numeric character in C++?
You can't. But the position is not hard to find:
auto last_non_numeric = input.find_last_not_of("1234567890");
char* endp = &input[0];
if (last_non_numeric != std::string::npos)
endp += last_non_numeric + 1;
if (*endp) { /* FAILURE, no number on the end */ }
auto i = strtol(endp, &endp, 10);
if (*endp) {/* weird FAILURE, maybe the number was really HUGE and couldn't convert */}
Another possibility would be to put the string into a stringstream, then read the number from the stream (after imbuing the stream with a locale that classifies everything except digits as white space).
// First the desired facet:
struct digits_only: std::ctype<char> {
digits_only(): std::ctype<char>(get_table()) {}
static std::ctype_base::mask const* get_table() {
// everything is white-space:
static std::vector<std::ctype_base::mask>
rc(std::ctype<char>::table_size,std::ctype_base::space);
// except digits, which are digits
std::fill(&rc['0'], &rc['9'], std::ctype_base::digit);
// and '.', which we'll call punctuation:
rc['.'] = std::ctype_base::punct;
return &rc[0];
}
};
Then the code to read the data:
std::istringstream virtuallive("Images1234");
virtuallive.imbue(locale(locale(), new digits_only);
int number;
// Since we classify the letters as white space, the stream will ignore them.
// We can just read the number as if nothing else were there:
virtuallive >> number;
This technique is useful primarily when the stream contains a substantial amount of data, and you want all the data in that stream to be interpreted in the same way (e.g., only read numbers, regardless of what else it might contain).

Same .txt files, different sizes?

I have a program that reads from a .txt file
I use the cmd prompt to execute the program with the name of the text file to read from.
ex: program.exe myfile.txt
The problem is that sometimes it works, sometimes it doesn't.
The original file is 130KB and doesn't work.
If I copy/paste the contents, the file is 65KB and works.
If I copy/paste the file and rename it, it's 130KB and doesn't work.
Any ideas?
After more testing it shows that this is what makes it not work:
int main(int argc, char *argv[])
{
char *infile1
char tmp[1024] = { 0x0 };
FILE *in;
for (i = 1; i < argc; i++) /* Skip argv[0] (program name). */
{
if (strcmp(argv[i], "-sec") == 0) /* Process optional arguments. */
{
opt = 1; /* This is used as a boolean value. */
/*
* The last argument is argv[argc-1]. Make sure there are
* enough arguments.
*/
if (i + 1 <= argc - 1) /* There are enough arguments in argv. */
{
/*
* Increment 'i' twice so that you don't check these
* arguments the next time through the loop.
*/
i++;
optarg1 = atoi(argv[i]); /* Convert string to int. */
}
}
else /* not -sec */
{
if (infile1 == NULL) {
infile1 = argv[i];
}
else {
if (outfile == NULL) {
outfile = argv[i];
}
}
}
}
in = fopen(infile1, "r");
if (in == NULL)
{
fprintf(stderr, "Unable to open file %s: %s\n", infile1, strerror(errno));
exit(1);
}
while (fgets(tmp, sizeof(tmp), in) != 0)
{
fprintf(stderr, "string is %s.", tmp);
//Rest of code
}
}
Whether it works or not, the code inside the while loop gets executed.
When it works tmp actually has a value.
When it doesn't work tmp has no value.
EDIT:
Thanks to sneftel, we know what the problem is,
For me to use fgetws() instead of fgets(), I need tmp to be a wchar_t* instead of a char*.
Type casting seems to not work.
I tried changing the declaration of tmp to
wchar_t tmp[1024] = { 0x0 };
but I realized that tmp is a parameter in strtok() used elsewhere in my code.
I here is what I tried in that function:
//tmp is passed as the first parameter in parse()
void parse(wchar_t *record, char *delim, char arr[][MAXFLDSIZE], int *fldcnt)
{
if (*record != NULL)
{
char*p = strtok((char*)record, delim);
int fld = 0;
while (p) {
strcpy(arr[fld], p);
fld++;
p = strtok('\0', delim);
}
*fldcnt = fld;
}
else
{
fprintf(stderr, "string is null");
}
}
But typecasting to char* in strtok doesn't work either.
Now I'm looking for a way to just convert the file from UTF-16 to UTF-8 so tmp can be of type char*
I found this which looks like it can be useful but in the example it uses input from the user as UTF-16, how can that input be taken from the file instead?
http://www.cplusplus.com/reference/locale/codecvt/out/
It sounds an awful lot like the original file is UTF-16 encoded. When you copy/paste it in your text editor, you then save the result out as a new (default encoding) (ASCII or UTF-8) text file. Since a single character takes 2 bytes in a UTF-16-encode file but only 1 byte in a UTF-8-encoded file, that results in the file size being roughly halved when you save it out.
UTF-16 is fine, but you'll need to use Unicode-aware functions (that is, not fgets) to work with it. If you don't want to deal with all that Unicode jazz right now, and you don't actually have any non-ASCII characters to deal with in the file, just do the manual conversion (either with your copy/paste or with a command-line utility) before running your program.

Is there a difference between \??\ and \\?\ paths?

The MSDN document Naming Files, Paths, and Namespaces talks about the \\?\ prefix. To quote:
For file I/O, the "\?\" prefix to a path string tells the Windows APIs to disable all string parsing and to send the string that follows it straight to the file system.
Experimentation showed me that the \??\ prefix has the same effect, both disabling path parsing (.. handling) and enabling paths longer than MAX_PATH.
The MSDN refers to \\? as the "Win32 file namespace", so does it known purely by the Win32 usermode API and translated to \?? in the NT namespace? And anyway, through Winobj I see GLOBAL?? in the NT namespace, not ??.
The answer to your question is, yes there is a difference between passing \\?\ and \??\ to user mode functions.
Internally, NT always represents paths with the \??\ prefix. Normally, when you call a user mode function (e.g. CreateDirectoryW) with a normal path like C:\foo, the user mode functions call an internal function named RtlDosPathNameToNtPathName_U which converts this to an NT-style path prefixed with \??\. This conversion is done with a fixed size static buffer, which is where the famous MAX_PATH limitation comes from.
When you call a user mode function specifying the \\?\ prefix (note, only one ?), RtlDosPathNameToNtPathName_U is not called. Instead, the second back-slash is turned into a ? character and the path is used verbatim. This is what the docs mean when they talk about \\?\ turning off the "...automatic expansion of the path string."
However, when you call a user mode function with the \??\ prefix, which remember is an internal NT prefix, this expansion is still done.
The user mode functions specifically look for \\?\ to disable the automatic expansion process, and since you're not providing it, your path is treated as a non-prefixed path and fed to RtlDosPathNameToNtPathName_U. This function is smart enough not to add an extra \??\ prefix to the start of the path, however the fixed size static buffer is still used.
This is the key difference. When you pass \??\ as a prefix your paths are still subject to the MAX_PATH length limit.
The following example program demonstrates this. The TestNestedDir function simply attempts to create (and then delete) a path greater than MAX_PATH characters in length, one level at a time. The results you'll see if you run this code are:
CreateDir, no prefix = 0
CreateDir, prefix \\?\ = 1
CreateDir, prefix \??\ = 0
Only the creation done with the \\?\ prefix is successful.
#include <stdio.h>
#include <tchar.h>
#include <string>
#include <assert.h>
#include <Windows.h>
const wchar_t* pszLongPath =
L"C:\\"
L"12345678901234567890123456789012345678901234567890\\"
L"12345678901234567890123456789012345678901234567890\\"
L"12345678901234567890123456789012345678901234567890\\"
L"12345678901234567890123456789012345678901234567890\\"
L"12345678901234567890123456789012345678901234567890\\"
L"12345678901234567890123456789012345678901234567890";
bool TestCreateNestedDir(LPCWSTR pszPath)
{
std::wstring strPath = pszPath;
std::wstring::size_type pos = 0, first = std::wstring::npos;
bool fDirs = false, fResult = false;
// step through each level in the path, but only try to start creating directories
// after seeing a : character
while ((pos = strPath.find_first_of(L'\\', pos)) != std::wstring::npos)
{
if (fDirs)
{
// get a substring for this level of the path
std::wstring strSub = strPath.substr(0, pos);
// check if the level already exists for some reason
DWORD dwAttr = ::GetFileAttributesW(strSub.c_str());
if (dwAttr != -1 && (dwAttr & FILE_ATTRIBUTE_DIRECTORY))
{
++pos;
continue;
}
// try to make the dir. if it exists, remember the first one we successfully made for later cleanup
if (!::CreateDirectoryW(strSub.c_str(), nullptr))
break;
if (first == std::wstring::npos) first = pos;
}
else
if (pos > 0 && strPath[pos - 1] == L':')
fDirs = true;
++pos;
}
if (pos == std::wstring::npos)
{
// try to create the last level of the path (we assume this one doesn't exist)
if (::CreateDirectoryW(pszPath, nullptr))
{
fResult = true;
::RemoveDirectoryW(pszPath);
}
}
else
--pos;
// now delete any dirs we successfully made
while ((pos = strPath.find_last_of(L'\\', pos)) != std::wstring::npos)
{
::RemoveDirectoryW(strPath.substr(0, pos).c_str());
if (pos == first) break;
--pos;
}
return fResult;
}
int _tmain(int argc, _TCHAR* argv[])
{
assert(wcslen(pszLongPath) > MAX_PATH);
printf("CreateDir, no prefix = %ld\n", TestCreateNestedDir(pszLongPath));
std::wstring strPrefix = L"\\\\?\\" + std::wstring(pszLongPath);
printf("CreateDir, prefix \\\\?\\ = %ld\n", TestCreateNestedDir(strPrefix.c_str()));
strPrefix[1] = L'?';
printf("CreateDir, prefix \\??\\ = %ld\n", TestCreateNestedDir(strPrefix.c_str()));
return 0;
}

Is there anyway to make SOMETHING automatically add selected file extension to filename, when OPENFILENAME struct and GetSaveFileName() are used?

I have this function:
void PickupFileAndSave(std::vector<unsigned char> file_data, int *error_code, char *file_mask = "All files (*.*)\0*.*\0\0")
{
OPENFILENAMEA ofn; // common dialog box structure
char szFile[MAX_PATH]; // buffer for file name
char initial_dir[MAX_PATH] = { 0 };
GetStartupPath(initial_dir);
// Initialize OPENFILENAME
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = GetActiveWindow();
ofn.lpstrFile = szFile;
// Set lpstrFile[0] to '\0' so that GetOpenFileName does not
// use the contents of szFile to initialize itself.
ofn.lpstrFile[0] = '\0';
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFilter = file_mask;
ofn.nFilterIndex = 1;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = initial_dir;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_EXPLORER;
if (!GetSaveFileNameA(&ofn))
{
*error_code = GetLastError();
return;
}
char err_msg[1024] = { 0 };
std::string file_name = ofn.lpstrFile; //this stores path to file without extension
file_name.append(".");
file_name.append(ofn.lpstrDefExt); //this is NULL and fails to copy too
WriteAllBytes(file_name.c_str(), &file_data[0], file_data.size(), &err_msg[0]);
if (strlen(err_msg) > 0)
{
*error_code = GetLastError();
return;
}
}
I call it that way:
int write_error = 0;
PickupFileAndSave(compressed, &write_error, "RLE compressed files (*.rle)\0*.rle\0\0");
When I choose file it shows in the filter needed extension, but do not add it to lpstrFile.
Any ideas why and how to fix it?
You did not assign lpstrDefExt so the system will not add the extension in case you omit it. So you simply need to initialise the field before you show the dialog:
lpstrDefExt = "rle";
The documentation explains this:
lpstrDefExt
The default extension. GetOpenFileName and GetSaveFileName append this extension to the file name if the user fails to type an extension. This string can be any length, but only the first three characters are appended. The string should not contain a period (.). If this member is NULL and the user fails to type an extension, no extension is appended.
It's not clear from the code in the question but you want to handle the case where there are multiple filters and you wish to append the extension of the selected filter.
The system won't do that for you so you will have to. Read nFilterIndex after you have shown the dialog. That tells you which filter the user selected. Then parse the filter string to obtain the chosen extension, and append it to the filename if it has no extension.

scanf_s throws exception

Why does the following code throw an exception when getting to the second scanf_s after entering an number to put into the struct.
This by no means represents a complete linked list implementation.
Not sure how to get onto the next scanf_s when having entered the value? Any ideas?
EDIT: Updated code with suggested solution, but still get an AccessViolationException after first scanf_s
Code:
struct node
{
char name[20];
int age;
float height;
node *nxt;
};
int FillInLinkedList(node* temp)
{
int result;
temp = new node;
printf("Please enter name of the person");
result = scanf_s("%s", temp->name);
printf("Please enter persons age");
result = scanf_s("%d", &temp->age); // Exception here...
printf("Please enter persons height");
result = scanf_s("%f", &temp->height);
temp->nxt = NULL;
if (result >0)
return 1;
else return 0;
}
// calling code
int main(array<System::String ^> ^args)
{
node temp;
FillInLinkedList(&temp);
...
You are using scanf_s with incorrect parameters. Take a look at the examples in the MSDN documentation for the function. It requires that you pass in the size of the buffer after the buffer for all string or character parameters. So
result = scanf_s("%s", temp->name);
should be:
result = scanf_s("%s", temp->name, 20);
The first call to scanf_s is reading garbage off the stack because it is looking for another parameter and possibly corrupting memory.
There is no compiler error because scanf_s uses a variable argument list - the function doesn't have a fixed number of parameters so the compiler has no idea what scanf_s is expecting.
You need
result = scanf_s("%d", &temp->age);
and
result = scanf_s("%f", &temp->height);
Reason is that sscanf (and friends) requires a pointer to the output variable so it can store the result there.
BTW, you have a similar problem with the parameter temp of your function. Since you're changing the pointer (and not just the contents of what it points to), you need to pass a double pointer so that the changes will be visible outside your function:
int FillInLinkedList(node** temp)
And then of course you'll have to make the necessary changes inside the function.
scanf() stores data into variables, so you need to pass the address of the variable (or its pointer)Example:
char string[10];
int n;
scanf("%s", string); //string actually points to address of
//first element of string array
scanf("%d", &n); // &n is the address of the variable 'n'
%19c should be %s
temp->age should be &temp-age
temp->height should be &temp->height
Your compiler should be warning you
about these errors
I believe you need to pass parameters to scanf() functions by address. i.e. &temp->age
otherwise temp-age will be interpreted as a pointer, which will most likely crash your program.

Resources