I am trying to save some files using C, with this code:
sprintf(playerinput,"%s",end);
sprintf(fileloc,"%s/.notend",getenv("HOME"));
playerdata = fopen(fileloc, "w+"); /*create the new file*/
if (!playerdata)
{
printf("\n\t\t\tCould not save settings file.");
return;
} else {
fputs(playerinput,playerdata);
fclose(playerdata);
}
It should set playerinput to the end variable, which works on Linux, then set the file location to the homearea/.notend, then make or edit the file, and put it out. In Linux (gcc), this works fine. The same code, however, on Windows (i586-mingw32msvc-gcc, does not work. Am I doing something wrong, or is another header file needed? Currently I have:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_NOTES 200
#define MAX_NAMES_TEXT 200
#define MAX_NOTES_TEXT 2000
as my headers and defines. If you need more information, just ask.
To which location are you trying to write your file? Does the application have the right permissions to write to that location?
EDIT: Looking at the path style you just defined C://Documents and Settings//..., you should try it with C:\\\\Documents and Settings\\.... Note that there's double backslash for each slash in the path. I'm not sure if fopen() would convert / to \, so it's worth a try.
If you're sure that this would be running on Windows Vista and above you can get this path using getenv("HOMEPATH"). I would suggest a macro definition like:
#ifdef _WIN32
# define HOME_ENV "HOMEPATH"
#else
# define HOME_ENV "HOME"
#endif
followed by:
getenv(HOME_ENV) to get the home directory for the user.
The environment variable HOME is not a default environment variable on Windows so:
getenv("HOME");
will return NULL. You need to use a different function to obtain a user's home directory on Windows, SHGetFolderPath will provide this:
char path[MAX_PATH + 1] = "";
if (SUCCEEDED(SHGetFolderPath(0,
CSIDL_LOCAL_APPDATA,
0,
SHGFP_TYPE_CURRENT,
path)))
{
std::cout << path << "\n";
}
This output:
C:\Documents and Settings\admin\Local Settings\Application Data
on my machine.
Related
I want to access the user name in the Windows using C programming and use that name to create the path to the particular file like "c:\users\john\Roaming.....and so on". So for every system user name e.g "john" is different. Help me to find the user name at run time.
#include <stdio.h>
int main(void)
{
printf("%s\n", getenv("USERPROFILE")); // Print user's home directory.
return 0;
}
To get the user name instead of the home path replace USERPROFILE with USERNAME.
What you are looking for, here, is probably more SHGetKnownFolderPath. The function lets you find per-user special folders. This is preferred to querying usernames because the home folder may not have the same name as the user.
WSTR* location;
HRESULT hr = SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, NULL, &location);
if (SUCCEEDED(hr))
{
// location contains the folder path
// call CoTaskMemFree to free up the memory once you're done with it
CoTaskMemFree(location);
}
The list of so-called known folders is available here.
The function to get user name on windows is GetUserName
This answer, probably, will help you too.
you could use the following code to get the Username.
#include <stdlib.h>
void main(void)
{
//following gets the appdata folder
char szAppData[1024];
char * szBufer = 0;
szBufer = getenv ("APPDATA");
if (szBufer != NULL)
{
strcpy(szBufer , szAppData);
}
//following code gets the user name
char szOSUserName[1024];
szBufer = getenv ("USERNAME");
if (szBufer != NULL)
{
strcpy(szBufer , szOSUserName);
}
}
You can get the name of the current user with GetUserName:
#include <Windows.h>
#include <Lmcons.h>
#include <stdio.h>
int main()
{
char name[UNLEN + 1];
DWORD cch = UNLEN + 1;
if (GetUserName(name, &cch))
{
char cmd[100 + UNLEN + 1];
sprintf(cmd, "echo The username is \"%s\"", name); // Silly demo command
system(cmd);
}
return 0;
}
Use GetUserNameEx if you want the name in a specific format.
If you need to get the path to a special folder like "My Documents" or "Desktop" you should use the special folder functions like SHGetFolderPath or SHGetKnownFolderPath.
%USERNAME% will give you the username, but a better solution is to store it on %USERPROFILE%\\Desktop\\key.txt to at least make it OS-independent.
And an even better solution would be not to store private information on the users' desktops. Or anywhere.
I have researched a lot on this topic but could not get anything substantial.
By normalize/canonicalize I mean to remove all the "..", ".", multiple slashes etc from a file path and get a simple absolute path.
e.g.
"/rootdir/dir1/dir2/dir3/../././././dir4//////////" to
"/rootdir/dir1/dir2/dir4"
On windows I have GetFullPathName() and I can get the canonical filepath name, but for Linux I cannot find any such API which can do the same work for me,
realpath() is there, but even realpath() needs the filepath to be present on the file system to be able to output normalized path, e.g. if the path /rootdir/dir1/dir2/dir4 is not on file system - realpath() will throw error on the above specified complex filepath input.
Is there any way by which one could get the normalized file path even if it is not existing on the file system?
realpath(3) does not resolve missing filenames.
But GNU core utilities (https://www.gnu.org/software/coreutils/) have a program realpath(1) which is similar to realpath(3) function, but have option:
-m, --canonicalize-missing no components of the path need exist
And your task can be done by canonicalize_filename_mode() function from file lib/canonicalize.c of the coreutils source.
canonicalize_filename_mode() from Gnulib is a great option but cannot be used in commercial software (GPL License)
We use the following implementation that depends on cwalk library:
#define _GNU_SOURCE
#include <unistd.h>
#include <stdlib.h>
#include "cwalk.h"
/* extended version of canonicalize_file_name(3) that can handle non existing paths*/
static char *canonicalize_file_name_missing(const char *path) {
char *resolved_path = canonicalize_file_name(path);
if (resolved_path != NULL) {
return resolved_path;
}
/* handle missing files*/
char *cwd = get_current_dir_name();
if (cwd == NULL) {
/* cannot detect current working directory */
return NULL;
}
size_t resolved_path_len = cwk_path_get_absolute(cwd, path, NULL, 0);
if (resolved_path_len == 0) {
return NULL;
}
resolved_path = malloc(resolved_path_len + 1);
cwk_path_get_absolute(cwd, path, resolved_path, resolved_path_len + 1);
free(cwd);
return resolved_path;
}
Is there a way to get the line number a function was called on in C without doing anything like below?
The define can make it tedious after a while, having to use DP instead of { like usual, and hard to read; but the adding LINE as the first parameter to every function is just something I'm not willing to do.
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#define println(x,...) printf(x,##__VA_ARGS__);printf("\n");
/*
*I would like to be able to replace __LINE__ with the line
*each function was called on, or replace my DP define completely...
*/
#ifdef _DEBUG_
#define DP { println("%s:%d\t%s()",__FILE__,__LINE__,__FUNCTION__);
#else
#define DP {
#endif
void calledFunc()
DP
println("something something something");
}
void cFunc(int line)
{
println("%s:%d\t%s()",__FILE__,line,__FUNCTION__);
}
int main()
DP
calledFunc();
/* ...and I don't want to have to do this all the time either*/
cFunc(__LINE__);
}
There is a good substitute for printing the line file name/number. It is called "LocationID" or LID.
LID is a number that is generated out the project wide counter. The latest value of the counter should be stored in the source file and checked in/out of the source control system like any other source file. The value of the counter can be scrambled. This forces its proper use. You use it like:
#ifdef _DEBUG_
#define DP(x, msg) println("%d: %s", x, msg);
#endif
and in your source:
DP (3517, "Here we are.")
Advantage of the LIDs are:
They are stable against modification of the source file, including renaming of the file/function.
They are easy to find in the sources.
Log file is much more compact and clear than with the file name and the function name.
I used this several times and it proved to be good. Generation and distribution of LID values among developers is an overhead, but the result is 10 times worth the price of this effort.
Basically, i have a program that is given a 4 meg compressed file, it has to decode this file into uncompressed ~ 100 meg, then compress it back into ~4 meg file. I need to store this intermediate 100 meg file somewhere on the drive (dont want to keep it in memory).
Program is written in C and will be executed on MS Windows 7. At the moment of uncompressing, no guaranteed folder (with write access) is given to the program (folder with source file might be read only and folder with target file might be not yet specified).
This has proven to be not an easy task:
1) I have read about a C function that creates a temp file that will disappear when closed or program is terminated. However, from what i understand it tries to make the file on disk C, in root directory, so this will obviously fail if user has no rights for that (which normal user doesnt)
2) I had an idea to use environmental/system variable TEMP and create a file there, BUT looking on a random Win7 PC which wasnt tweaked, i see that this variable points to c:/windows/temp, and that folder has specific rights for "users" - that is, they have rights to read, execute, create and write files, but not to delete them, check their attributes, etc. This means, i assume, that if program is ran with user privilleges, it will be able to make a file but not able to delete it, so the only way to "delete" it would be to open the file for writing and then close it, making it a 0 length file. This is also not desired, and i dont know how to query for system variables from C
3) So, basically, only idea i have right now is to make a function to open file that:
tries to create a temp file in the output dir, if possible
if failed, tries to create a temp file in input dir
if failed, tries to create a temp file in TEMP dir from system variable
if failed, tries to create a temp file in TMP dir from system variable
and a delete function that:
tries to remove() the file (by its name that is stored somewhere)
if failed, it tries to open the file for write, and close it, so it becomes a 0 byte file
Are there better ideas?
Any help is appreciated, thanks!
PS: Program must not use any external libraries like MFC or something, only built-in standart C functions
GetTempPath
Retrieves the path of the directory designated for temporary files.
GetTempFileName
Creates a name for a temporary file. If a unique file name is
generated, an empty file is created and the handle to it is released;
otherwise, only a file name is generated.
These two provide you easy way to obtain a location and name for a temporary file.
UPD: Code sample on MSDN: Creating and Using a Temporary File.
#include <windows.h>
#include <iostream>
#include <chrono>
#include <string>
#include <cstdio>
#include <chrono>
using namespace std;
int FileExists(string& filepath)
{
DWORD dwAttrib = GetFileAttributes(filepath.c_str());
return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
!(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
}
int GetTemporaryFilePath(
string filePrefix,
string fileExt,
string& TmpFilePath /*return*/)
{
if (fileExt[0] == '.')
fileExt.erase(0,1);
char TempPath[MAX_PATH] = { 0 };
if (!GetTempPath(MAX_PATH, TempPath))
return -1;
uint16_t tickint = 0;
while(1) {
const int nowlen = 17; char nowstr[nowlen];
const int ticklen = 5; char tickstr[ticklen];
// Milliseconds since 1970
auto ms = chrono::duration_cast<chrono::milliseconds>(
chrono::system_clock::now().time_since_epoch()
);
__int64 nowint = ms.count();
snprintf(nowstr, nowlen, "%016" "I64" "x", nowint);
snprintf(tickstr, ticklen, "%04x", tickint);
TmpFilePath = string(TempPath)
+ filePrefix
+ "." + string(nowstr)
+ "." + string(tickstr)
+ "." + fileExt;
if (!FileExists(TmpFilePath)) {
//Touch File
FILE* w = fopen(TmpFilePath.c_str(), "w");
fclose(w);
break;
}
tickint++;
}
return 0;
}
int main()
{
string TmpFilePath;
GetTemporaryFilePath("MyFile", ".txt", TmpFilePath);
cout << "TmpFilePath: " << TmpFilePath << endl;
return 0;
}
I just started working with C & Xcode and I've run into a little difficulty.
All I want to do is read a file from the command line and see the output in the terminal.
I think my problem lies with the path to the file that I want to read in. I'm using a Mac and the file is on my desktop, so the path should be Users/myName/Desktop/words.txt. Is this correct?
This is my code:
#import <Foundation/Foundation.h>
int main (int argc, const char* argv[]){
if(argc == 1){
NSLog(#" you must pass at least one arguement");
return 1;
}
NSLog(#"russ");
FILE* wordFile = fopen(argv[1] , "r");
char word[100];
while (fgets(word,100,wordFile)) {
NSLog(#" %s is %d chars long", word,strlen(word));
}
fclose(wordFile);
return 0;
}//main
If you need the path to a file in OS X, an easy way to get it is to just drag the file into the Terminal.app window where you are typing the command. Voila!
The path to the desktop is /Users/[username]/Desktop/
~/Desktop/ is a user-agnostic way of denoting this, ~ represents the current users home directory. It must be expanded using a method like stringByExpandingTildeInPath
Not sure about using C# (I've never used it on Mac OS X), but in Objective-C/Cocoa, you would do..
// Get array with first index being path to desktop
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDesktopDirectory, NSUserDomainMask, YES);
// Get the first element
NSString *desktopPath = [paths objectAtIndex:0];
// Append words.txt to path
NSString *theFilePath = [desktopPath stringByAppendingPathComponent:#"words.txt"];
NSLog(#"%#", theFilePath);
This is the most robust way of getting the Desktop path, as a user could technically move their Desktop folder else where (although this is pretty unlikely). Another valid option is to use the NSString method stringByExpandingTildeInPath:
NSString *desktop = [#"~/Desktop" stringByExpandingTildeInPath];
NSString *theFile = [desktop stringByAppendingPathComponent:#"words.txt"]
As I said, both those are in Objective-C, but it shouldn't be hard to translate to C#, assuming you can get at the Cocoa libraries.
The code you posted works correctly:
dbr:.../build/Debug $ ./yourcode ~/Desktop/words.txt
yourcode[2106:903] russ
yourcode[2106:903] this is words.txt is 17 chars long
Your terminal automatically expands the ~/ tilda path
Close... it's
/{Volume}/Users/myName/Desktop/words.txt
... where {Volume} is the name of your hard drive. You can also try using:
~/Desktop/words.txt
... where ~ is understood to mean "your home directory", but this might not resolve correctly.
(Note - this appears to be a C question, not a C# question)
Actually, you can do:
/Users/myName/Desktop/words.txt
You don't have to give the path to the volume.
However, to get the full path in C you'd do something like:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char *home, *fullPath;
home = getenv("HOME");
fullPath = strcat(home, "/Desktop/words.txt");
The issue you're running into with passing the filename as an argument is that you need to set the current working directory to the place where the file exists.