I must note that developing code for windows platform is a mystery for me at the moment.
I have an issue with going through a directory and reading up files, where polish characters are present. Following code snippets work on windows in english and polish version, but not in german. What's the reason? I've tried with POSIX opendir() / readdir() and with winapi FindFirstFile() / FindNextFile() functions. They gave same results.
Consider following program. It reads up files ( in POSIX and winapi way ) within test directory and prints them out.
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <dirent.h>
int main(void)
{
char* name;
name = _getcwd(NULL, 0);
char* tmp = realloc(name, strlen(name)*2);
if (tmp != NULL) {
name = tmp;
}
else {
perror("realloc");
free(name);
exit(1);
}
strcat(name, "\\test");
DIR* dir = opendir(name);
struct dirent* s;
while ((s = readdir(dir)) != NULL) {
printf("%s\n", s->d_name);
}
closedir(dir);
free(s);
strcat(name, "\\*");
HANDLE dir_w;
WIN32_FIND_DATA s_w;
if ((dir_w = FindFirstFile(name, &s_w)) != INVALID_HANDLE_VALUE) {
while (FindNextFile(dir_w, &s_w) != 0) {
printf("%s\n", s_w.cFileName);
}
}
FindClose(dir_w);
free(name);
return 0;
}
ISSUE : on windows with german language polish characters are interpreted as ASCII characters. If, for example, file has name:
ąęćś.txt
then on english language windows it is read up correctly, but on german one is read as
aecs.txt
but such file does not exist. Should I go with wchar_t type and functions specific to it (FindNextFilew) ? I don't have german windows so it is hard for me to reproduce the error. I've been trying to change code page with command chcp 1250 but that didn't help. Setting locale to pl also did not help.
Compiler: gcc 5.0.0
The C standard library functions you call will be using ANSI encoded text which as I'm sure you know cannot handle international text.
So you'll want to use the native Unicode Windows APIs rather than the legacy ANSI versions. That means wchar_t based functions with W prefixes like FindFirstFileW. For a start you should enable the Unicode conditionals so that the FindFirstFile macro expands to FindFirstFileW.
Related
I am learning how to write a simple CGI page with C language. I tried with Apache on both Linux and Windows. I compiled my scripts on 2 different computers that run different OSes.
Firstly, I created a simple CGI page for getting a static plain-text content:
#include
int main()
{
FILE *fp = fopen("plain_text.txt", "r"); // text-mode only.
if (fp)
{
int ch;
printf("content-type: text/plain\n\n");
while ((ch = fgetc(fp)) != EOF)
{
printf("%c", ch);
}
fclose(fp);
}
return 0;
}
I compiled it into an executable and put it in cgi-bin directory. When I browse it with my web-browser, it returns the plain-text content correctly (both Linux and Windows).
Then, I modified above script for getting a simple JPEG content.
(I understand that: every JPEG picture is a binary file)
#include
int main()
{
FILE *fp = fopen("cat_original.jpg", "rb"); // with binary-mode.
if (fp)
{
int ch;
printf("content-type: image/jpg\n\n");
while (((ch = fgetc(fp)) != EOF) || (!feof(f1))) // can read whole content of any binary file.
{
printf("%c", ch);
}
fclose(fp);
}
return 0;
}
I compiled it into an executable and put it in cgi-bin directory, too.
I can get the correct returned-image with Linux compiled-executable files; but, the Windows does not.
To understand the problem, I downloaded the returned-image with Windows compiled-execute files.
(I named this image: cat_downloaded_windows.jpg)
Then, I used VBinDiff for compare 2 images: cat_original.jpg (68,603 bytes) and cat_downloaded_windows.jpg (68,871 bytes).
There are many lines in cat_downloaded_windows.jpg (like the row I marked) have a character which cat_original.jpg does not have.
VBinDiff
So, I guess that the Windows OS causes the problem (Windows add some characters automatically, and Linux does not)
(Apache and web-browsers do not cause problem)
So, I posted this topic into StackOverflow for getting your helps. I have 2 questions:
Is there any problem with the printf("%c", ch); (in my script) on Windows?
Is there any way to print binary content into stdout, both Linux and Windows?
I am learning programming myself, and this is the first time I ask on StakOverflow.
So, if my question is not clear, please comment below this question; I will try to explain it more.
Thank you for your time!
When you use printf() to write to standard output, it is working in text mode, not binary mode, so every time your program encounters a newline \n in the JPEG file, it writes \r\n on Windows, which corrupts the JPEG file.
You'll need to know how to put standard output into binary mode and you'll need to ensure that you generate \r\n in place of \n in the headers.
The MSDN documentation says you can use _setmode(), and shows an example (setting stdin instead of stdout):
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
int main(void)
{
int result;
// Set "stdin" to have binary mode:
result = _setmode(_fileno(stdin), _O_BINARY);
if (result == -1)
perror("Cannot set mode");
else
printf("'stdin' successfully changed to binary mode\n");
}
First of all, I'm a complete novice at programming, especially in C. The example I'm going to show is code I've snagged from this site and
kicked until it didn't quite do what I wanted. :)
Second, I'm using a dual-core Celeron with Linux Mint and the GNU C Compiler.
What I want to do is list the subdirectories within a directory, skipping the parent directory if any. Unfortunately, the code I have
doesn't work. I tried strcpy and strncpy, but I couldn't figure out how to use them and I just screwed up the code so that I got a
"segmentation fault" when I tried to run the program.
Here's the code:
/*
* This program displays the names of all files in the current directory.
*/
#include <dirent.h>
#include <string.h>
#include <stdio.h>
int main(void)
{
DIR *d;
struct dirent *dir;
char dirname[255];
d = opendir(".");
if (d)
{
while ((dir = readdir(d)) != NULL)
{
if (dir->d_type == DT_DIR)
{
strncpy(dirname, dir->d_name, 254);
dirname[254] = '\0';
if (dirname != "..") /* I want to skip this, but it doesn't work */
{
printf ("%s\n", dirname);
}
}
}
closedir(d);
}
return(0);
}
Thanks for any help you can give. I'd especially be interested in links to sites that can offer tutorials that would help me with this
little project, as I want a better understanding of what the heck I'm doing. :)
In C, to compare strings you need to use either strcmp or strncmp.
if (strcmp(dirname, "..") != 0) { ... }
What is the correct way to read and extract data from text files when you know that there will be many in a directory? I know that you can use fopen() to get the pointer to the file, and then do something like while(fgets(..) != null){} to read from the entire file, but then how could I read from another file? I want to loop through every file in the directory.
Sam, you can use opendir/readdir as in the following little function.
#include <stdio.h>
#include <dirent.h>
static void scan_dir(const char *dir)
{
struct dirent * entry;
DIR *d = opendir( dir );
if (d == 0) {
perror("opendir");
return;
}
while ((entry = readdir(d)) != 0) {
printf("%s\n", entry->d_name);
//read your file here
}
closedir(d);
}
int main(int argc, char ** argv)
{
scan_dir(argv[1]);
return 0;
}
This just opens a directory named on the command line and prints the names of all files it contains. But instead of printing the names, you can process the files as you like...
Typically a list of files is provided to your program on the command line, and thus are available in the array of pointers passed as the second parameter to main(). i.e. the invoking shell is used to find all the files in the directory, and then your program just iterates through argv[] to open and process (and close) each one.
See p. 162 in "The C Programming Language", Kernighan and Ritchie, 2nd edition, for an almost complete template for the code you could use. Substitute your own processing for the filecopy() function in that example.
If you really need to read a directory (or directories) directly from your program, then you'll want to read up on the opendir(3) and related functions in libc. Some systems also offer a library function called ftw(3) or fts(3) that can be quite handy too.
I am working on TTCN-3 (Testing and Test Control Notation) scripting language. I wanted to prepare on guideline checker for this code files.
For that I want to read lines of TTCN-3 script file( some thing like file.ttcn ) one by one into a buffer. But for me fopen / sopen / open / fgetc / fscanf are not able to work properly and are not reading the file correctly. It is giving NULL. Is there any way I can read characters of it into a buffer. I think C cannot read files with more than three extension characters (like .ttcn). Forgive me if my assumption is wrong.
My Environment is Turbo C on windows.
Edit:
Yes I checked those errors also but they are giving unknown error for read()
and no such file or directory exists.
My code is as follows
#include <errno.h>
#include <io.h>
#include <fcntl.h>
#include <sys\stat.h>
#include <process.h>
#include <share.h>
#include <stdio.h>
int main(void)
{
int handle;
int status;
int i=0;
char ch;
FILE *fp;
char *buffer;
char *buf;
clrscr();
handle = sopen("c:\\tc\\bin\\hi.ttcn", O_BINARY, SH_DENYNONE, S_IREAD);
/here even I used O_TEXT and others/
if (!handle)
{
printf("sopen failed\n");
// exit(1);
}
printf("\nObtained string %s #",buf);
close(handle);
fp=fopen("c:\\tc\\bin\\hi.ttcn","r"); \\sorry for the old version of one slash
if(fp==NULL) \\I was doing it with argv[1] for opening
{ \\user given file name
printf("\nCannot open file");
}
ch=fgetc(fp);
i=0;
while(i<10)
{
printf("\ncharacter is %c %d",ch,ch);
i++; //Here I wanted to take characters into
ch=fgetc(fp); //buffer
}
getch();
return 0;
}
The most likely culprit is your Turbo C, an ancient compiler. It's techincally a DOS compiler, not Windows. That would limit it's RunTme Library to 8.3 filenames. Upgrade to something newer - Turbo C++ seems like a logical successor, but Microsoft's VC++ Express would work as well.
Your assumption is wrong about extensions. If fopen is returning NULL, you should output the result of strerror(errno) or use the perror() function to see why it failed.
Edit: The problem is probably because you have "c:\tc\bin\hi.ttcn". in C, "\t" is interpreted as tab, for example.
You could do
"c:\\tc\\bin\\hi.ttcn"
But this is extremely ugly, and your system should accept:
"c:/tc/bin/hi.ttcn"
MS-DOS does not know about long file names, thos including files with extensions longer than 3 characters. Therefore, the CRT provided by Turbo C most probably does not look for the name you are providing, but a truncated one - or something else.
Windows conveniently provides a short (i.e. matching the 8.3 format, most of the time ending in ~1 unless you play with files having the same 8-character prefix) file name for those; one way to discover it is to open a console window and to run "dir /x" in the folder your file is stored.
Find the short name associated to your file and patch it into your C source file.
Edit: Darn, I'll read the comments next time. All credits to j_random_hacker.
Now that you've posted the code, another problem comes to light.
The following line:
fp=fopen("c:\tc\bin\hi.ttcn","r");
Should instead read:
fp=fopen("c:\\tc\\bin\\hi.ttcn","r");
In C strings, the backslash (\) is an escape character that is used to encode special characters (e.g. \n represents a newline character, \t a tab character). To actually use a literal backslash, you need to double it. As it stands, the compiler is actually trying to open a file named "C:<tab>c<backspace>in\hi.ttcn" -- needless to say, no such file exists!
How do you scan a directory for folders and files in C? It needs to be cross-platform.
The following POSIX program will print the names of the files in the current directory:
#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
int main (void)
{
DIR *dp;
struct dirent *ep;
dp = opendir ("./");
if (dp != NULL)
{
while ((ep = readdir (dp)) != NULL)
puts (ep->d_name);
(void) closedir (dp);
return 0;
}
else
{
perror ("Couldn't open the directory");
return -1;
}
}
Credit: http://www.gnu.org/software/libtool/manual/libc/Simple-Directory-Lister.html
Tested in Ubuntu 16.04.
The strict answer is "you can't", as the very concept of a folder is not truly cross-platform.
On MS platforms you can use _findfirst, _findnext and _findclose for a 'c' sort of feel, and FindFirstFile and FindNextFile for the underlying Win32 calls.
Here's the C-FAQ answer:
http://c-faq.com/osdep/readdir.html
I've created an open source (BSD) C header that deals with this problem. It currently supports POSIX and Windows. Please check it out:
https://github.com/cxong/tinydir
tinydir_dir dir;
tinydir_open(&dir, "/path/to/dir");
while (dir.has_next)
{
tinydir_file file;
tinydir_readfile(&dir, &file);
printf("%s", file.name);
if (file.is_dir)
{
printf("/");
}
printf("\n");
tinydir_next(&dir);
}
tinydir_close(&dir);
There is no standard C (or C++) way to enumerate files in a directory.
Under Windows you can use the FindFirstFile/FindNextFile functions to enumerate all entries in a directory. Under Linux/OSX use the opendir/readdir/closedir functions.
GLib is a portability/utility library for C which forms the basis of the GTK+ graphical toolkit. It can be used as a standalone library.
It contains portable wrappers for managing directories. See Glib File Utilities documentation for details.
Personally, I wouldn't even consider writing large amounts of C-code without something like GLib behind me. Portability is one thing, but it's also nice to get data structures, thread helpers, events, mainloops etc. for free
Jikes, I'm almost starting to sound like a sales guy :) (don't worry, glib is open source (LGPL) and I'm not affiliated with it in any way)
opendir/readdir are POSIX. If POSIX is not enough for the portability you want to achieve, check Apache Portable Runtime
Directory listing varies greatly according to the OS/platform under consideration. This is because, various Operating systems using their own internal system calls to achieve this.
A solution to this problem would be to look for a library which masks this problem and portable. Unfortunately, there is no solution that works on all platforms flawlessly.
On POSIX compatible systems, you could use the library to achieve this using the code posted by Clayton (which is referenced originally from the Advanced Programming under UNIX book by W. Richard Stevens). this solution will work under *NIX systems and would also work on Windows if you have Cygwin installed.
Alternatively, you could write a code to detect the underlying OS and then call the appropriate directory listing function which would hold the 'proper' way of listing the directory structure under that OS.
The most similar method to readdir is probably using the little-known _find family of functions.
You can find the sample code on the wikibooks link
/**************************************************************
* A simpler and shorter implementation of ls(1)
* ls(1) is very similar to the DIR command on DOS and Windows.
**************************************************************/
#include <stdio.h>
#include <dirent.h>
int listdir(const char *path)
{
struct dirent *entry;
DIR *dp;
dp = opendir(path);
if (dp == NULL)
{
perror("opendir");
return -1;
}
while((entry = readdir(dp)))
puts(entry->d_name);
closedir(dp);
return 0;
}
int main(int argc, char **argv) {
int counter = 1;
if (argc == 1)
listdir(".");
while (++counter <= argc) {
printf("\nListing %s...\n", argv[counter-1]);
listdir(argv[counter-1]);
}
return 0;
}