Code snippets
Favourite C definitions | ||
Microsoft C favourites |
||
_countof() | #define _countof(array)
(sizeof(array)/sizeof(array[0])) /* lifted from afximpl.h */ |
Gives the number of elements in an given array. Aka. ELEMENTS. Useful everywhere, especially in these times of Unicode. |
EXTERN_C | #ifndef EXTERN_C #ifdef __cplusplus #define EXTERN_C extern "C" #else #define EXTERN_C extern #endif #endif /* lifted from objbase.h */ |
For prototyping functions. Useful when mixing C and C++ code - indispensable actually. |
offsetof | #define offsetof(s,m)\ (size_t)&(((s *)0)->m) /* resides in stddef.h */ |
Sadly overlooked gem. |
Homegrown favourites (C + MFC) |
||
SafeStrlen() | #define SafeStrlen(lpsz) ( (
(LPCTSTR)(lpsz) == NULL) ? 0 : lstrlen(lpsz) ) /* clone of CString::SafeStrlen. Cast ensures safe SafeStrlen(CString) - and SafeStrlen(std::string.c_str() :) ) */ |
To some, it's cleaner to pass around NULL than ubiquitous _T("")
- that is, a pointer to just _T('\0'), allocated for in the static data 'segment'. Anyway, this macro's safe and typesafe (yields warning if pointer isn't LPCTSTR)! |
__argc, __argv |
#ifdef _MSDOS extern int __argc; extern TCHAR** __argv; #endif |
__argc and __argv isn't prototyped anywhere in antiquated Microsoft compilers. They're practical to have in scope, also outside of main(). |
ParamStr() | #define ParamStr(a) (__argc > a) ? __argv[a] : _T("") | It's safer! |
IsWinNT() | #ifdef _WIN32 #ifdef _UNICODE #define IsWinNT() TRUE #else #define IsWinNT() ((GetVersion() & 0xC0000000) == 0) #endif #else /* Win16 */ #define WF_WINNT 0x4000 #define IsWinNT() ((GetWinFlags() & WF_WINNT) == WF_WINNT) #endif |
How to detect NT, also from within Win16 apps. |
DECLARE_ CONSOLEAPP (MFC) |
#ifdef _CONSOLE #define DECLARE_CONSOLEAPP \ extern int AFXAPI\ AfxWinMain(HINSTANCE hInstance,\ HINSTANCE hPrevInstance,\ LPTSTR lpCmdLine, int nCmdShow);\ extern "C" int _tmain( int /*argc*/,\ TCHAR** /*argv*/, TCHAR** /*envp*/)\ {\ return AfxWinMain(\ GetModuleHandle(NULL), NULL,\ GetCommandLine(), SW_SHOW);\ } // remember to instantiate app class #endif // _CONSOLE |
How to use CCommandLine and CWinApp in console apps. See Console app. |
Program samples | |
MFC: Console app |
- using CCommandLine and CWinApp in console apps. |
C: Safer strncpy/cat |
- get them now, or suffer later. strncpy/cat doesn't always zero-terminate strings! |
Borland Pascal: File object |
- Encapsulation of System.Assign/System.Reset/System.Rewrite/System.IOResult. (I haven't tested it with Delphi, and I don't know whether Delphi offers something similar.) |
EXTERN_C char*
strncatz( char* strDest, const char* strSource, size_t count);
EXTERN_C char*
strncpyz( char* strDest, const char* strSource, size_t count);
#ifdef _WIN32
EXTERN_C wchar_t*
wcsncatz( wchar_t* strDest, const wchar_t* strSource, size_t count);
EXTERN_C wchar_t*
wcsncpyz( wchar_t* strDest, const wchar_t* strSource, size_t count);
#endif
#ifdef _UNICODE
#define _tcsncatz wcscatz
#define _tcsncpyz wcscpyz
#else
#define _tcsncatz strcatz
#define _tcsncpyz strcpyz
#endif
char* strncatz( char* strDest, const char* strSource,
size_t count)
/* safe strcat (always zero-terminated ) */
{
const int length = strlen(strDest);
char* lpsz = strncat(strDest, strSource, count - length - 1);
lpsz[count - 1] = _T('\0');
return lpsz;
}
char* strncpyz( char* strDest, const char* strSource,
size_t count)
/* safe strcpy (always zero-terminated ) */
{
char* lpsz = strncpy(strDest, strSource, min(strlen(strSource) + 1, count) );
lpsz[count - 1] = _T('\0');
return lpsz;
}
#ifdef _WIN32
wchar_t* wcsncatz( wchar_t* strDest, const wchar_t* strSource, size_t count)
/* safe strcat (always zero-terminated ) */
{
const int length = wcslen(strDest);
wchar_t* lpsz = wcsncat(strDest, strSource, count - length - 1);
lpsz[count - 1] = _T('\0');
return lpsz;
}
wchar_t* wcsncpyz( wchar_t* strDest, const wchar_t* strSource, size_t count)
/* safe strncpy (always zero-terminated ) */
{
wchar_t* lpsz = wcsncpy(strDest, strSource, min(wcslen(strSource) + 1, count) );
lpsz[count - 1] = _T('\0');
return lpsz;
}
#endif
Unit TFileUnt;
Interface
Uses Objects, Dos, Crt;
Type ByteFile = File Of Byte; PDateTime = ^DateTime; Str2 = String[2]; Str80 = String[80]; sz3 = Array [0.. 2] Of Char; sz512 = Array [0.. 511] Of Char;
Const FILE_MODE_CREATE = 1; FILE_MODE_READ = 2; FILE_MODE_WRITE = 4; FILE_MODE_READWRITE = 6;
FILE_SEEK_END = 1; { End of file } FILE_SEEK_CUR = 2; { Current position of file pointer } FILE_SEEK_SET = 3; { Beginning of file }
Type TFile = Object(TObject) private m_hfile : ByteFile; m_bOpen : Boolean; m_bFromHandle : Boolean; m_sFileName : PathStr; m_nOpenFlags : Word; m_nError : Integer; m_bIOError : Boolean; { IOResult or DOSError error } public { Construction / Destruction } Constructor Init; Destructor Done; Virtual; Function Open (sFileName : PathStr; nOpenFlags : Word) : Boolean; Virtual; Function Close : Boolean;
{ I/O } Function Read (pDest : Pointer; nByteCount : Word) : Word; Function Write (pSrc : Pointer; nByteCount : Word) : Word; Virtual;
{ Misc. helpers } Function Remove : Boolean; Function Rename(sNewName : PathStr) : Boolean; Function Seek(nByteCount : LongInt; nOffset : Integer) : Boolean; Function GetSize : LongInt; Function GetPos : LongInt; Function SetTime(dt : DateTime ) : Boolean; Function GetTime(pDest : PDateTime) : Boolean; Function GetName : PathStr; Function GetDrive : Char; Function IsError : Boolean; Function GetError : Integer; private Function SetError(bIOError : Boolean) : Boolean; End;
TIncFile = Object(TFile) private m_nInc : LongInt; public Constructor Init(nInc : LongInt); Function Open(sFileName : PathStr; nOpenFlags : Word) : Boolean; Virtual; Function Write(pSrc : Pointer; nByteCount : Word) : Word; Virtual; Function GetInc : LongInt; Procedure DoIncrement; End;
TTextFile = Object(TFile) public Procedure WriteStr(s : String); Procedure WriteLn (s : String); Procedure WriteStrZ(psz : PChar); Procedure WriteLnZ (psz : PChar); Function ReadLn : Str80; End;
Function IsDrivePresent (d : char) : Boolean; Function IsDriveReadOnly(d : char) : Boolean; Function GetDriveFree (d : char) : LongInt; { d = #0 -> default drive } Function RemoveFile(sFileName : PathStr) : Boolean; { wildcards ok } Function CopyFile(sDest, sSrc : PathStr) : Boolean; Function MoveFile(sDest, sSrc : PathStr) : Boolean; { smart - renames if on same drive } Function SetFileTime(sFileName : PathStr; dt : DateTime ) : Boolean; Function GetFileTime(sFileName : PathStr; pDest : PDateTime) : Boolean; Function FileExists(sFileName : PathStr): Boolean;
{ helpers } Function memset(pDest : Pointer; c : Integer; nCount : Word) : Pointer; Function memmove(pDest, pSrc : Pointer; nCount : Word) : Pointer; Function UpperCaseStr(s : Str80) : Str80; Function UpperCaseChar(c : char) : char;
Implementation
Uses Strings;
Const PASCAL_FILE_MODE_READ = 0; PASCAL_FILE_MODE_WRITE = 1; PASCAL_FILE_MODE_READWRITE = 2; PASCAL_FILE_MODE_DEFAULT = PASCAL_FILE_MODE_READWRITE;
Constructor TFile.Init; Begin TObject.Init; m_bOpen := FALSE; m_bFromHandle := FALSE; m_sFileName := ''; m_nOpenFlags := 0; m_nError := 0; DOS.DOSError := 0; End;
Destructor TFile.Done; Begin if((m_bOpen) And (Not m_bFromHandle)) then Close; TObject.Done; End;
Function TFile.IsError : Boolean; Begin IsError := m_nError <> 0; End;
Function TFile.GetError : Integer; Begin GetError := m_nError; End;
Function TFile.SetError(bIOError : Boolean) : Boolean; { called after *every* Pascal IO operation } Begin if(bIOError) then m_nError := System.IOResult { Pascal does only return the last error *once* } else m_nError := DOS.DOSError; DOS.DOSError := 0; SetError := IsError; End;
Function TFile.Open(sFileName : PathStr; nOpenFlags : Word) : Boolean; Begin Open := FALSE; m_sFileName := UpperCaseStr(FExpand(sFileName)); { make sure that it's a full path }
m_nOpenFlags := nOpenFlags; if(((nOpenFlags And FILE_MODE_CREATE) = 0) And (Not FileExists(m_sFileName))) Then exit;
System.Assign(m_hfile, m_sFileName); if(SetError(TRUE)) then exit; if( ((nOpenFlags And FILE_MODE_CREATE) <> 0) ) then {$I-} System.Rewrite(m_hfile) {$I+} else Begin if(((nOpenFlags And FILE_MODE_READ ) <> 0) And ((nOpenFlags And FILE_MODE_WRITE) <> 0)) then System.FileMode := PASCAL_FILE_MODE_READWRITE else if((nOpenFlags And FILE_MODE_READ ) <> 0) then System.FileMode := PASCAL_FILE_MODE_READ else System.FileMode := PASCAL_FILE_MODE_WRITE; System.Reset(m_hfile); System.FileMode := PASCAL_FILE_MODE_DEFAULT; End; if(SetError(TRUE)) then exit; m_bOpen := TRUE; Open := TRUE; End;
Function TFile.GetName : PathStr; Begin GetName := m_sFileName; End;
Function TFile.GetDrive : Char; Begin GetDrive := m_sFileName[1]; End;
Function TFile.Close : Boolean; Begin Close := FALSE; if(m_bOpen) then Begin System.Close(m_hfile); Close := Not SetError(TRUE); End; m_bOpen := FALSE; End;
Function TFile.Read (pDest : Pointer; nByteCount : Word) : Word;
Var result : Word;
Begin System.BlockRead(File(m_hfile), pDest^, nByteCount * SizeOf(Byte), result); Read := result; End;
Function TFile.Write(pSrc : Pointer; nByteCount : Word) : Word;
Var result : Word;
Begin System.BlockWrite(File(m_hfile), pSrc^, nByteCount * SizeOf(Byte), result); Write := result; End;
Function TFile.Remove : Boolean; Begin Remove := FALSE; if(m_bOpen) then if(Not Close) then exit; System.Erase(m_hfile); Remove := Not SetError(TRUE); End;
Function TFile.Rename(sNewName : PathStr) : Boolean; Begin Rename := FALSE; if(Not Close) then exit; m_sFileName := UpperCaseStr(FExpand(sNewName)); { make sure that it's a full path } System.Rename(m_hfile, m_sFileName); Rename := Not SetError(TRUE); End;
Function TFile.Seek(nByteCount : LongInt; nOffset : Integer) : Boolean;
Var p : LongInt;
Begin case(nOffset) of FILE_SEEK_END : p := GetSize - nByteCount; FILE_SEEK_CUR : p := GetPos + nByteCount; FILE_SEEK_SET : p := 0 + nByteCount; else p := 0; End; System.Seek(m_hFile, p); Seek := Not SetError(TRUE); End;
Function TFile.GetSize : LongInt; Begin GetSize := System.FileSize(m_hfile); End;
Function TFile.GetPos : LongInt; Begin GetPos := System.FilePos(m_hfile); End;
Function TFile.GetTime(pDest : PDateTime) : Boolean;
Var t : LongInt;
Begin DOS.GetFTime(m_hfile, t); UnpackTime(t, pDest^); GetTime := Not SetError(FALSE); { DOSError ? } End;
Function TFile.SetTime(dt : DateTime ) : Boolean;
Var t : LongInt;
Begin { Pascal bug - 47 sec's becomes 46 !! } PackTime(dt, t); DOS.SetFTime(m_hfile, t); SetTime := Not SetError(FALSE); { DOSError ? } End;
Function IsDrivePresent(d : char) : Boolean; Begin IsDrivePresent := -1 <> Dos.DiskFree(Ord(UpperCaseChar(d)) - Ord('A') + 1); End;
Function GetDriveFree(d : char) : LongInt;
Function GetDefaultDrive : Char;
Var s : String;
Begin GetDir(0, s); GetDefaultDrive := s[1]; End;
Begin If(d = #0) then d := GetDefaultDrive ; GetDriveFree := DiskFree(Ord(UpperCaseChar(d)) - Ord('A') + 1); End;
Procedure TTextFile.WriteStr(s : String); Begin Write(@s[1], Length(s)); End;
Procedure TTextFile.WriteLn(s : String); Begin s := s + #13 + #10; WriteStr(s); End;
Procedure TTextFile.WriteStrZ(psz : PChar); Begin Write(psz, strlen(psz)); End;
Procedure TTextFile.WriteLnZ (psz : PChar);
Const szCrLf : sz3 = #13 + #10;
Var sz : sz512;
Begin strcopy(sz, psz); strcat(sz, szCrLf); WriteStrZ(sz); End;
Function TTextFile.ReadLn : Str80;
Var p : LongInt; len : Byte ; s2 : str2; s : Str80;
Begin p := GetPos; s2 := '12'; while((s2 <> #13 + #10) And (s2 <> #10 + #13)) do Begin if(2 <> Read(@s2[1], 2)) then break; Seek(-1, FILE_SEEK_CUR); End; s := ''; if((s2 = #13 + #10) Or (s2 = #10 + #13)) then Begin len := GetPos - p - 1; Seek(p, FILE_SEEK_SET); s[0] := Char(len); Read(@s [1], len); Read(@s2[1], 2); End else Seek(p, FILE_SEEK_SET); ReadLn := s; End;
Constructor TIncFile.Init(nInc : LongInt); Begin TFile.Init; m_nInc := nInc; End;
Function TIncFile.Open(sFileName : PathStr; nOpenFlags : Word) : Boolean; Begin Open := FALSE; if(Not TFile.Open(sFileName, nOpenFlags)) then exit; if(GetSize < m_nInc) then DoIncrement; Open := TRUE; End;
Procedure TIncFile.DoIncrement;
Const BLOCKSIZE = 8192;
Var p : Pointer; nBlockSize : Word; nByteCount : LongInt; nOldPos : LongInt;
Begin nOldPos := GetPos; nBlockSize := BLOCKSIZE; If(nBlockSize > m_nInc) then nBlockSize := m_nInc; GetMem(p, nBlockSize); { get dummy data block } memset(p, 0, nBlockSize); { zero it } nByteCount := 0; Seek(0, FILE_SEEK_END); while(nByteCount < m_nInc - nBlockSize) do begin TFile.Write(p, nBlockSize); inc(nByteCount, nBlockSize); end; nByteCount := m_nInc - nByteCount; if(nByteCount > 0) then { write the rest } TFile.Write(p, nByteCount); FreeMem(p, nBlockSize);
{ close and re-open } Close; TFile.Open(m_sFileName, m_nOpenFlags And (Not FILE_MODE_CREATE)); Seek(nOldPos, FILE_SEEK_SET); { return pointer } End;
Function TIncFile.Write(pSrc : Pointer; nByteCount : Word) : Word; Begin Write := 0; if(GetPos + nByteCount > GetSize) then Begin if(GetDriveFree(GetDrive) > m_nInc) then DoIncrement { add dummy block at end } else exit; { no room - exit and return 0 } End; Write := TFile.Write(pSrc, nByteCount); End;
Function TIncFile.GetInc : LongInt; Begin GetInc := m_nInc; End;
Function CopyFile(sDest, sSrc : PathStr) : Boolean;
Const BLOCKSIZE = 8192;
Var fDest, fSrc : TFile;
Procedure DoCopy;
Var p : Pointer; nBlockSize : Word; dt : DateTime;
Begin GetMem(p, nBlockSize); { get dummy data block } nBlockSize := BLOCKSIZE; while(nBlockSize = BLOCKSIZE) do begin nBlockSize := fSrc.Read(p, BLOCKSIZE); fDest.Write(p, nBlockSize); end; FreeMem(p, nBlockSize); fSrc .GetTime(@dt); fDest.SetTime(dt); End;
Begin fSrc .Init; fDest.Init; CopyFile := FALSE; if (fSrc .Open(sSrc , FILE_MODE_READ) And fDest.Open(sDest, FILE_MODE_CREATE or FILE_MODE_READWRITE)) then Begin DoCopy; CopyFile := TRUE; End; fSrc .Done; fDest.Done; End;
Function MoveFile(sDest, sSrc : PathStr) : Boolean;
Function IsSameDrive : Boolean;
Var sPath1 , sPath2 : PathStr;
Begin sPath1 := DOS.FExpand(sSrc); sPath2 := DOS.FExpand(sDest); IsSameDrive := UpperCaseChar(sPath1[1]) = UpperCaseChar(sPath2[1]); End;
Function JustRename : Boolean;
Var f : TFile; dt : DateTime;
Begin f.Init; JustRename := FALSE; if (f.Open(sSrc , FILE_MODE_READWRITE)) then Begin f.GetTime(@dt); JustRename := f.Rename(sDest); { closes f } if(f.Open(sDest, FILE_MODE_READWRITE)) then { re-open and set time } f.SetTime(dt); End; f.Done; End;
Begin MoveFile := FALSE; if(IsSameDrive) then { if on same drive, simple renaming will do } Begin MoveFile := JustRename; exit; End; if(Not CopyFile(sDest, sSrc)) then exit; MoveFile := RemoveFile(sSrc); End;
Function SetFileTime(sFileName : PathStr; dt : DateTime ) : Boolean;
Var f : TFile;
Begin SetFileTime := FALSE; f.Init; if(f.Open(sFileName, FILE_MODE_WRITE)) then SetFileTime := f.SetTime(dt); f.Done; End;
Function GetFileTime(sFileName : PathStr; pDest : PDateTime) : Boolean;
Var f : TFile;
Begin GetFileTime := FALSE; f.Init; if(f.Open(sFileName, FILE_MODE_READ)) then GetFileTime := f.GetTime(pDest); f.Done; End;
Function RemoveFile(sFileName : PathStr) : Boolean; { remove one or more files }
var sr : SearchRec; bOK : Boolean; f : TFile; sDir : DirStr; sName : NameStr; { Not used } sExt : ExtStr; { Not used }
Begin f.Init; DOS.FSplit(sFileName, sDir, sName, sExt); DOS.FindFirst(sFileName, Archive, sr); bOK := DosError = 0; while(DosError = 0) do begin if(f.Open(sDir + sr.Name, FILE_MODE_WRITE)) then bOK := bOK And f.Remove; DOS.FindNext(sr); end; f.Done; RemoveFile := bOK; End;
function FileExists(sFileName : PathStr) : Boolean; { Boolean function that returns True if the file exists; otherwise, it returns False. Closes the file if it exists. }
Var f : file;
Begin FileExists := FALSE; if(sFileName = '') then exit; {$I-} System.Assign(f, sFileName); System.FileMode := PASCAL_FILE_MODE_READ; System.Reset(F); System.Close(F); {$I+} System.FileMode := PASCAL_FILE_MODE_DEFAULT; FileExists := (System.IOResult = 0); End; { FileExists }
Function IsDriveReadOnly(d : char) : Boolean;
Var f : file;
Begin IsDriveReadOnly := FALSE; {$I-} System.Assign(f, d + ':\plzualzw.azq'); System.FileMode := PASCAL_FILE_MODE_READWRITE; System.Rewrite(f); System.Close(f); {$I+} System.FileMode := PASCAL_FILE_MODE_DEFAULT; if(System.IOResult = 0) then { was created - not read only} Begin System.Erase(f); exit; End; IsDriveReadOnly := TRUE; End; { FileExists }
Function UpperCaseChar(c : char) : char; begin Case(c) of '' : UpperCaseChar := ''; '' : UpperCaseChar := ''; '' : UpperCaseChar := ''; else UpperCaseChar := UpCase(c); end; end;
Function UpperCaseStr(s : Str80) : Str80;
Var a:integer;
begin For a := 1 to Length(s) do s[a] := UpperCaseChar(s[a]); UpperCaseStr := s; end;
Function memset(pDest : Pointer; c : Integer; nCount : Word) : Pointer; Begin System.FillChar(pDest^, nCount, c); memset := pDest; End;
Function memmove(pDest, pSrc : Pointer; nCount : Word) : Pointer; Begin move(pSrc^, pDest^, nCount); memmove := pDest; End;
Begin end.
This page © Troels Knakkergaard. Updated march 30rd 1999