Merge pull request #2202 from akruphi/readme
[far2l.git] / multiarc / src / ArcMix.cpp
blob86898f2291c157592648b5d2a236fbe240a48230
1 #include "MultiArc.hpp"
2 #include "marclng.hpp"
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <unistd.h>
7 #include <sys/stat.h>
8 #include <windows.h>
9 #include <string>
10 #include <vector>
12 extern std::string gMultiArcPluginPath;
14 BOOL FileExists(const char *Name)
16 struct stat s = {0};
17 return sdc_stat(Name, &s) != -1;
20 static void mystrlwr(char *p)
22 for (; *p; ++p)
23 *p = tolower(*p);
26 static void mystrupr(char *p)
28 for (; *p; ++p)
29 *p = toupper(*p);
32 BOOL GoToFile(const char *Target, BOOL AllowChangeDir)
34 if (!Target || !*Target)
35 return FALSE;
36 BOOL rc = FALSE, search = TRUE;
37 PanelRedrawInfo PRI;
38 PanelInfo PInfo;
39 char Name[NM], Dir[NM * 5];
40 int pathlen;
42 ArrayCpyZ(Name, FSF.PointToName(const_cast<char *>(Target)));
43 pathlen = (int)(FSF.PointToName(const_cast<char *>(Target)) - Target);
44 if (pathlen)
45 memcpy(Dir, Target, pathlen);
46 Dir[pathlen] = 0;
48 FSF.Trim(Name);
49 FSF.Trim(Dir);
50 FSF.Unquote(Name);
51 FSF.Unquote(Dir);
53 Info.Control(INVALID_HANDLE_VALUE, FCTL_UPDATEPANEL, (void *)1);
54 Info.Control(INVALID_HANDLE_VALUE, FCTL_GETPANELINFO, &PInfo);
55 pathlen = strlen(Dir);
56 if (pathlen) {
57 if (*PInfo.CurDir && PInfo.CurDir[strlen(PInfo.CurDir) - 1] != '/' // old path != "*\"
58 && Dir[pathlen - 1] == '/')
59 Dir[pathlen - 1] = 0;
61 if (0 != strcmp(Dir, PInfo.CurDir)) {
62 if (AllowChangeDir) {
63 Info.Control(INVALID_HANDLE_VALUE, FCTL_SETPANELDIR, &Dir);
64 Info.Control(INVALID_HANDLE_VALUE, FCTL_GETPANELINFO, &PInfo);
65 } else
66 search = FALSE;
70 PRI.CurrentItem = PInfo.CurrentItem;
71 PRI.TopPanelItem = PInfo.TopPanelItem;
72 if (search) {
73 for (int J = 0; J < PInfo.ItemsNumber; J++) {
74 if (!strcmp(Name, FSF.PointToName(PInfo.PanelItems[J].FindData.cFileName))) {
75 PRI.CurrentItem = J;
76 PRI.TopPanelItem = J;
77 rc = TRUE;
78 break;
82 return rc ? Info.Control(INVALID_HANDLE_VALUE, FCTL_REDRAWPANEL, &PRI) : FALSE;
85 int __isspace(int Chr)
87 return Chr == 0x09 || Chr == 0x0A || Chr == 0x0B || Chr == 0x0C || Chr == 0x0D || Chr == 0x20;
90 const char *GetMsg(int MsgId)
92 return Info.GetMsg(Info.ModuleNumber, MsgId);
95 #ifdef HAVE_UNRAR
96 int rar_main(int argc, char *argv[]);
97 #endif
98 extern "C" int sevenz_main(int argc, char *argv[]);
99 extern "C" int ha_main(int argc, char *argv[]);
101 #ifdef HAVE_LIBARCHIVE
102 extern "C" int libarch_main(int numargs, char *args[]);
103 #endif
105 SHAREDSYMBOL int BuiltinMain(int argc, char *argv[])
107 if (!argc)
108 return -1;
110 int r = -2;
112 if (strcmp(argv[0], "7z") == 0) {
113 r = sevenz_main(argc, &argv[0]);
114 #ifdef HAVE_UNRAR
115 } else if (strcmp(argv[0], "rar") == 0) {
116 r = rar_main(argc, &argv[0]);
117 #endif
118 } else if (strcmp(argv[0], "7z") == 0) {
119 r = sevenz_main(argc, &argv[0]);
120 } else if (strcmp(argv[0], "ha") == 0) {
121 r = ha_main(argc, &argv[0]);
122 #ifdef HAVE_LIBARCHIVE
123 } else if (strcmp(argv[0], "libarch") == 0) {
124 r = libarch_main(argc, &argv[0]);
125 #endif
126 } else
127 fprintf(stderr, "BuiltinMain: bad target '%s'\n", argv[0]);
128 return r;
131 /* $ 13.09.2000 tran
132 запуск треда для ожидания момента убийства лист файла */
133 #if 0
134 static DWORD WINAPI ThreadWhatWaitingForKillListFile(LPVOID par)
136 KillStruct *ks=(KillStruct*)par;
138 WINPORT(WaitForSingleObject)(ks->hProcess,INFINITE);
139 WINPORT(CloseHandle)(ks->hThread);
140 WINPORT(CloseHandle)(ks->hProcess);
141 sdc_unlink(ks->ListFileName);
142 free((LPVOID)ks);
143 return SUPER_PUPER_ZERO;
145 void StartThreadForKillListFile(PROCESS_INFORMATION *pi,char *list)
147 if ( pi==0 || list==0 || *list==0)
148 return;
149 KillStruct *ks;
150 DWORD dummy;
152 ks=(KillStruct*)malloc(GPTR,sizeof(KillStruct));
153 if ( ks==0 )
154 return ;
156 ks->hThread=pi->hThread;
157 ks->hProcess=pi->hProcess;
158 strcpy(ks->ListFileName,list);
160 WINPORT(CloseHandle)(WINPORT(CreateThread)(NULL,0xf000,ThreadWhatWaitingForKillListFile,ks,0 ,&dummy));
163 /* tran 13.09.2000 $ */
164 #endif
166 int Execute(HANDLE hPlugin, const std::string &CmdStr, int HideOutput, int Silent, int NeedSudo,
167 int ShowCommand, char *ListFileName)
169 if (!CmdStr.empty() && (CmdStr[0] == ' ' || CmdStr[0] == '\t')) { // FSF.LTrim(ExpandedCmd); //$ AA 12.11.2001
170 std::string CmdStrTrimmed = CmdStr;
171 do {
172 CmdStrTrimmed.erase(0, 1);
173 } while (!CmdStrTrimmed.empty() && (CmdStrTrimmed[0] == ' ' || CmdStrTrimmed[0] == '\t'));
175 return Execute(hPlugin, CmdStrTrimmed, HideOutput, Silent, NeedSudo, ShowCommand, ListFileName);
178 int ExitCode, LastError;
180 HANDLE StdInput = NULL;
181 HANDLE StdOutput = NULL;
182 HANDLE hScreen = NULL;
183 CONSOLE_SCREEN_BUFFER_INFO csbi;
185 if (HideOutput) {
186 if (!Silent) {
187 hScreen = Info.SaveScreen(0, 0, -1, -1);
188 const char *MsgItems[] = {"", GetMsg(MWaitForExternalProgram)};
189 Info.Message(Info.ModuleNumber, 0, NULL, MsgItems, ARRAYSIZE(MsgItems), 0);
191 } else {
192 WINPORT(GetConsoleScreenBufferInfo)(StdOutput, &csbi);
194 char Blank[1024];
195 FSF.sprintf(Blank, "%*s", csbi.dwSize.X, "");
196 for (int Y = 0; Y < csbi.dwSize.Y; Y++)
197 Info.Text(0, Y, LIGHTGRAY, Blank);
198 Info.Text(0, 0, 0, NULL);
200 COORD C;
201 C.X = 0;
202 C.Y = csbi.dwCursorPosition.Y;
203 WINPORT(SetConsoleCursorPosition)(StdOutput, C);
206 DWORD ConsoleMode;
207 WINPORT(GetConsoleMode)(StdInput, &ConsoleMode);
208 WINPORT(SetConsoleMode)
209 (StdInput, ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT);
211 WCHAR SaveTitle[512]{};
212 WINPORT(GetConsoleTitle)(NULL, SaveTitle, ARRAYSIZE(SaveTitle) - 1);
213 if (ShowCommand)
214 WINPORT(SetConsoleTitle)(NULL, StrMB2Wide(CmdStr).c_str());
216 /* $ 14.02.2001 raVen
217 делать окошку minimize, если в фоне */
218 /* if (Opt.Background)
220 si.dwFlags=si.dwFlags | STARTF_USESHOWWINDOW;
221 si.wShowWindow=SW_MINIMIZE;
223 /* raVen $ */
224 DWORD flags = (HideOutput) ? EF_HIDEOUT : 0;
225 if (NeedSudo)
226 flags|= EF_SUDO;
227 if (!ShowCommand)
228 flags|= EF_NOCMDPRINT;
230 if (*CmdStr.c_str() == '^') {
231 LastError = ExitCode =
232 FSF.ExecuteLibrary(gMultiArcPluginPath.c_str(), "BuiltinMain", CmdStr.c_str() + 1, flags);
233 } else {
234 LastError = ExitCode = FSF.Execute(CmdStr.c_str(), flags);
237 WINPORT(SetLastError)(LastError);
238 WINPORT(SetConsoleTitle)(NULL, SaveTitle);
239 WINPORT(SetConsoleMode)(StdInput, ConsoleMode);
240 if (hScreen) {
241 Info.RestoreScreen(NULL);
242 Info.RestoreScreen(hScreen);
245 return ExitCode;
248 char *QuoteText(char *Str)
250 int LastPos = strlen(Str);
251 memmove(Str + 1, Str, LastPos + 1);
252 Str[LastPos + 1] = *Str = '"';
253 Str[LastPos + 2] = 0;
254 return Str;
257 void InitDialogItems(const struct InitDialogItem *Init, struct FarDialogItem *Item, int ItemsNumber)
259 int I;
260 struct FarDialogItem *PItem = Item;
261 const struct InitDialogItem *PInit = Init;
262 for (I = 0; I < ItemsNumber; I++, PItem++, PInit++) {
263 PItem->Type = PInit->Type;
264 PItem->X1 = PInit->X1;
265 PItem->Y1 = PInit->Y1;
266 PItem->X2 = PInit->X2;
267 PItem->Y2 = PInit->Y2;
268 PItem->Focus = PInit->Focus;
269 PItem->History = (const char *)PInit->Selected;
270 PItem->Flags = PInit->Flags;
271 PItem->DefaultButton = PInit->DefaultButton;
272 strcpy(PItem->Data,
273 ((DWORD_PTR)PInit->Data < 2000) ? GetMsg((unsigned int)(DWORD_PTR)PInit->Data) : PInit->Data);
277 std::string NumberWithCommas(unsigned long long Number)
279 std::string out = std::to_string(Number);
280 for (int I = int(out.size()) - 4; I >= 0; I-= 3)
281 out.insert(I + 1, 1, ',');
283 return out;
286 int MA_ToPercent(int32_t N1, int32_t N2)
288 if (N1 > 10000) {
289 N1/= 100;
290 N2/= 100;
292 if (N2 == 0)
293 return 0;
294 if (N2 < N1)
295 return 100;
296 return (int)(N1 * 100 / N2);
299 int MA_ToPercent(int64_t N1, int64_t N2)
301 if (N1 > 10000) {
302 N1/= 100;
303 N2/= 100;
305 if (N2 == 0)
306 return 0;
307 if (N2 < N1)
308 return 100;
309 return (int)(N1 * 100 / N2);
312 int IsCaseMixed(const char *Str)
314 while (*Str && !isalpha(*Str))
315 Str++;
316 int Case = islower(*Str);
317 while (*(Str++))
318 if (isalpha(*Str) && islower(*Str) != Case)
319 return TRUE;
320 return FALSE;
323 int CheckForEsc()
325 WORD KeyCode = VK_ESCAPE;
326 return WINPORT(CheckForKeyPress)(NULL, &KeyCode, 1, CFKP_KEEP_OTHER_EVENTS) != 0;
329 char *GetCommaWord(char *Src, char *Word, char Separator)
331 int WordPos, SkipBrackets;
332 if (*Src == 0)
333 return NULL;
334 SkipBrackets = FALSE;
335 for (WordPos = 0; *Src != 0; Src++, WordPos++) {
336 if (*Src == '[' && strchr(Src + 1, ']') != NULL)
337 SkipBrackets = TRUE;
338 if (*Src == ']')
339 SkipBrackets = FALSE;
340 if (*Src == Separator && !SkipBrackets) {
341 Word[WordPos] = 0;
342 Src++;
343 while (__isspace(*Src))
344 Src++;
345 return Src;
346 } else
347 Word[WordPos] = *Src;
349 Word[WordPos] = 0;
350 return Src;
353 int FindExecuteFile(char *OriginalName, char *DestName, int SizeDest)
355 std::string cmd = "which ";
356 cmd+= OriginalName;
357 FILE *f = popen(cmd.c_str(), "r");
358 if (f == NULL) {
359 perror("FindExecuteFile - popen");
360 return FALSE;
362 if (!fgets(DestName, SizeDest - 1, f))
363 DestName[0] = 0;
364 else
365 DestName[SizeDest - 1] = 0;
366 pclose(f);
368 char *e = strchr(DestName, '\n');
369 if (e)
370 *e = 0;
371 e = strchr(DestName, '\r');
372 if (e)
373 *e = 0;
374 return DestName[0] ? TRUE : FALSE;
377 char *SeekDefExtPoint(char *Name, char *DefExt /*=NULL*/, char **Ext /*=NULL*/)
379 FSF.Unquote(Name); //$ AA 15.04.2003 для правильной обработки имен в кавычках
380 Name = FSF.PointToName(Name);
381 char *TempExt = strrchr(Name, '.');
382 if (!DefExt)
383 return TempExt;
384 if (Ext)
385 *Ext = TempExt;
386 return (TempExt != NULL) ? (strcasecmp(TempExt + 1, DefExt) ? NULL : TempExt) : NULL;
389 BOOL AddExt(char *Name, char *Ext)
391 char *ExtPnt;
392 FSF.Unquote(Name); //$ AA 15.04.2003 для правильной обработки имен в кавычках
393 if (Name && *Name && !SeekDefExtPoint(Name, Ext, &ExtPnt)) {
394 // transform Ext
395 char NewExt[NM], *Ptr;
396 strncpy(NewExt, Ext, sizeof(NewExt) - 1);
398 int Up = 0, Lw = 0;
399 Ptr = Name;
400 while (*Ptr) {
401 if (isalpha(*Ptr)) {
402 if (islower(*Ptr))
403 Lw++;
404 if (isupper(*Ptr))
405 Up++;
407 ++Ptr;
410 if (Lw)
411 mystrlwr(NewExt);
412 else if (Up)
413 mystrupr(NewExt);
415 if (ExtPnt && !*(ExtPnt + 1))
416 strcpy(ExtPnt + 1, NewExt);
417 else
418 FSF.sprintf(Name + strlen(Name), ".%s", NewExt);
419 return TRUE;
421 return FALSE;
424 #ifdef _NEW_ARC_SORT_
425 void WritePrivateProfileInt(char *Section, char *Key, int Value, char *Ini)
427 char Buf32[32];
428 wsprintf(Buf32, "%d", Value);
429 WritePrivateProfileString(Section, Key, Buf32, Ini);
431 #endif
433 int WINAPI GetPassword(char *Password, const char *FileName)
435 char Prompt[2 * NM], InPass[512];
436 FSF.sprintf(Prompt, GetMsg(MGetPasswordForFile), FileName);
437 if (Info.InputBox((const char *)GetMsg(MGetPasswordTitle), (const char *)Prompt, NULL, NULL, InPass,
438 sizeof(InPass), NULL, FIB_PASSWORD | FIB_ENABLEEMPTY)) {
439 strcpy(Password, InPass);
440 return TRUE;
442 return FALSE;
445 // Number of 100 nanosecond units from 01.01.1601 to 01.01.1970
446 #define EPOCH_BIAS I64(116444736000000000)
448 void WINAPI UnixTimeToFileTime(DWORD time, FILETIME *ft)
450 *(int64_t *)ft = EPOCH_BIAS + time * I64(10000000);
453 int GetScrX(void)
455 CONSOLE_SCREEN_BUFFER_INFO ConsoleScreenBufferInfo;
456 if (WINPORT(GetConsoleScreenBufferInfo)(NULL, &ConsoleScreenBufferInfo)) // GetStdHandle(STD_OUTPUT_HANDLE)
457 return ConsoleScreenBufferInfo.dwSize.X;
458 return 0;
461 int PathMayBeAbsolute(const char *Path)
463 return (Path && *Path == '/');
467 преобразует строку
468 "cdrecord-1.6.1/mkisofs-1.12b4/../cdrecord/cd_misc.c"
470 "cdrecord-1.6.1/cdrecord/cd_misc.c"
472 void NormalizePath(const char *lpcSrcName, char *lpDestName)
474 char *DestName = lpDestName;
475 char *Ptr;
476 char *SrcName = strdup(lpcSrcName);
477 char *oSrcName = SrcName;
478 int dist;
480 while (*SrcName) {
481 Ptr = strchr(SrcName, '/');
483 if (!Ptr)
484 Ptr = SrcName + strlen(SrcName);
486 dist = (int)(Ptr - SrcName) + 1;
488 if (dist == 1 && (*SrcName == '/')) {
489 *DestName = *SrcName;
490 DestName++;
491 SrcName++;
492 } else if (dist == 2 && *SrcName == '.') {
493 SrcName++;
495 if (*SrcName == 0)
496 DestName--;
497 else
498 SrcName++;
499 } else if (dist == 3 && *SrcName == '.' && SrcName[1] == '.') {
500 if (!PathMayBeAbsolute(lpDestName)) {
501 char *ptrCurDestName = lpDestName, *Temp = NULL;
503 for (; ptrCurDestName < DestName - 1; ptrCurDestName++) {
504 if (*ptrCurDestName == '/')
505 Temp = ptrCurDestName;
508 if (!Temp)
509 Temp = lpDestName;
511 DestName = Temp;
512 } else {
513 if (SrcName[2] == '/')
514 SrcName++;
517 SrcName+= 2;
518 } else {
519 strncpy(DestName, SrcName, dist);
520 dist--;
521 DestName+= dist;
522 SrcName+= dist;
525 *DestName = 0;
528 free(oSrcName);
531 std::string &NormalizePath(std::string &path)
533 std::vector<char> dest(std::max((size_t)MAX_PATH, path.size()) + 1);
534 NormalizePath(path.c_str(), &dest[0]);
535 path = &dest[0];
536 return path;
539 std::string &ExpandEnv(std::string &str)
541 Environment::ExpandString(str, false);
542 return str;
545 bool CanBeExecutableFileHeader(const unsigned char *Data, int DataSize)
547 if (DataSize < 16)
548 return false;
550 if (Data[0] == 0x7f && Data[1] == 'E' && Data[2] == 'L' && Data[3] == 'F')
551 return true;
553 if (Data[0] == 'M' && Data[1] == 'Z')
554 return true;
556 if (Data[0] == 'Z' && Data[1] == 'M')
557 return true;
559 if (Data[0] == 0xca && Data[1] == 0xfe && Data[2] == 0xba && Data[3] == 0xbe)
560 return true;
562 if (Data[0] == 0xfe && Data[1] == 0xed && Data[2] == 0xfa && (Data[3] == 0xce || Data[3] == 0xcf))
563 return true;
565 if (Data[3] == 0xfe && Data[2] == 0xed && Data[1] == 0xfa && (Data[0] == 0xce || Data[0] == 0xcf))
566 return true;
568 return false;