void CommandData::ReadConfig() { StringList List; if (ReadTextFile(DefConfigName,&List,true)) { wchar *Str; while ((Str=List.GetString())!=NULL) { while (IsSpace(*Str)) Str++; if (wcsnicomp(Str,L"switches=",9)==0) ProcessSwitchesString(Str+9); if (*Command!=0) { wchar Cmd[16]; wcsncpyz(Cmd,Command,ASIZE(Cmd)); wchar C0=toupperw(Cmd[0]); wchar C1=toupperw(Cmd[1]); if (C0=='I' || C0=='L' || C0=='M' || C0=='S' || C0=='V') Cmd[1]=0; if (C0=='R' && (C1=='R' || C1=='V')) Cmd[2]=0; wchar SwName[16+ASIZE(Cmd)]; swprintf(SwName,ASIZE(SwName),L"switches_%ls=",Cmd); size_t Length=wcslen(SwName); if (wcsnicomp(Str,SwName,Length)==0) ProcessSwitchesString(Str+Length); } } } }
int Ask(const wchar *AskStr) { Alarm(); const int MaxItems=10; wchar Item[MaxItems][40]; int ItemKeyPos[MaxItems],NumItems=0; for (const wchar *NextItem=AskStr;NextItem!=NULL;NextItem=wcschr(NextItem+1,'_')) { wchar *CurItem=Item[NumItems]; wcsncpyz(CurItem,NextItem+1,ASIZE(Item[0])); wchar *EndItem=wcschr(CurItem,'_'); if (EndItem!=NULL) *EndItem=0; int KeyPos=0,CurKey; while ((CurKey=CurItem[KeyPos])!=0) { bool Found=false; for (int I=0;I<NumItems && !Found;I++) if (toupperw(Item[I][ItemKeyPos[I]])==toupperw(CurKey)) Found=true; if (!Found && CurKey!=' ') break; KeyPos++; } ItemKeyPos[NumItems]=KeyPos; NumItems++; } for (int I=0;I<NumItems;I++) { eprintf(I==0 ? (NumItems>4 ? L"\n":L" "):L", "); int KeyPos=ItemKeyPos[I]; for (int J=0;J<KeyPos;J++) eprintf(L"%c",Item[I][J]); eprintf(L"[%c]%ls",Item[I][KeyPos],&Item[I][KeyPos+1]); } eprintf(L" "); wchar Str[50]; getwstr(Str,ASIZE(Str)); wchar Ch=toupperw(Str[0]); for (int I=0;I<NumItems;I++) if (Ch==Item[I][ItemKeyPos[I]]) return I+1; return 0; }
inline uint touppercw(uint ch) { #if defined(_UNIX) return(ch); #else return(toupperw(ch)); #endif }
inline uint touppercw(uint ch,bool ForceCase) { if (ForceCase) return(ch); #if defined(_UNIX) return(ch); #else return(toupperw(ch)); #endif }
void CommandData::ParseDone() { if (FileArgs.ItemsCount()==0 && !FileLists) FileArgs.AddString(MASKALL); wchar CmdChar=toupperw(Command[0]); bool Extract=CmdChar=='X' || CmdChar=='E' || CmdChar=='P'; if (Test && Extract) Test=false; // Switch '-t' is senseless for 'X', 'E', 'P' commands. // Suppress the copyright message and final end of line for 'lb' and 'vb'. if ((CmdChar=='L' || CmdChar=='V') && Command[1]=='B') BareOutput=true; }
uint CommandData::GetExclAttr(const wchar *Str) { if (IsDigit(*Str)) return wcstol(Str,NULL,0); uint Attr=0; while (*Str!=0) { switch(toupperw(*Str)) { #ifdef _UNIX case 'D': Attr|=S_IFDIR; break; case 'V': Attr|=S_IFCHR; break; #elif defined(_WIN_ALL) || defined(_EMX) case 'R': Attr|=0x1; break; case 'H': Attr|=0x2; break; case 'S': Attr|=0x4; break; case 'D': Attr|=0x10; break; case 'A': Attr|=0x20; break; #endif } Str++; } return Attr; }
void CmdExtract::ExtrPrepareName(Archive &Arc,const wchar *ArcFileName,wchar *DestName,size_t DestSize) { wcsncpyz(DestName,Cmd->ExtrPath,DestSize); // We need IsPathDiv check here to correctly handle Unix forward slash // in the end of destination path in Windows: rar x arc dest/ if (*Cmd->ExtrPath!=0 && !IsPathDiv(*PointToLastChar(Cmd->ExtrPath))) { // Destination path can be without trailing slash if it come from GUI shell. AddEndSlash(DestName,DestSize); } #ifndef SFX_MODULE if (Cmd->AppendArcNameToPath) { wcsncatz(DestName,PointToName(Arc.FirstVolumeName),DestSize); SetExt(DestName,NULL,DestSize); AddEndSlash(DestName,DestSize); } #endif #ifndef SFX_MODULE size_t ArcPathLength=wcslen(Cmd->ArcPath); if (ArcPathLength>0) { size_t NameLength=wcslen(ArcFileName); ArcFileName+=Min(ArcPathLength,NameLength); while (*ArcFileName==CPATHDIVIDER) ArcFileName++; if (*ArcFileName==0) // Excessive -ap switch. { *DestName=0; return; } } #endif wchar Command=Cmd->Command[0]; // Use -ep3 only in systems, where disk letters are exist, not in Unix. bool AbsPaths=Cmd->ExclPath==EXCL_ABSPATH && Command=='X' && IsDriveDiv(':'); // We do not use any user specified destination paths when extracting // absolute paths in -ep3 mode. if (AbsPaths) *DestName=0; if (Command=='E' || Cmd->ExclPath==EXCL_SKIPWHOLEPATH) wcsncatz(DestName,PointToName(ArcFileName),DestSize); else wcsncatz(DestName,ArcFileName,DestSize); wchar DiskLetter=toupperw(DestName[0]); if (AbsPaths) { if (DestName[1]=='_' && IsPathDiv(DestName[2]) && DiskLetter>='A' && DiskLetter<='Z') DestName[1]=':'; else if (DestName[0]=='_' && DestName[1]=='_') { // Convert __server\share to \\server\share. DestName[0]=CPATHDIVIDER; DestName[1]=CPATHDIVIDER; } } }
void CommandData::ParseArg(wchar *Arg) { if (IsSwitch(*Arg) && !NoMoreSwitches) if (Arg[1]=='-' && Arg[2]==0) NoMoreSwitches=true; else ProcessSwitch(Arg+1); else if (*Command==0) { wcsncpyz(Command,Arg,ASIZE(Command)); *Command=toupperw(*Command); // 'I' and 'S' commands can contain case sensitive strings after // the first character, so we must not modify their case. // 'S' can contain SFX name, which case is important in Unix. if (*Command!='I' && *Command!='S') wcsupper(Command); } else if (*ArcName==0) wcsncpyz(ArcName,Arg,ASIZE(ArcName)); else { // Check if last character is the path separator. size_t Length=wcslen(Arg); wchar EndChar=Length==0 ? 0:Arg[Length-1]; bool EndSeparator=IsDriveDiv(EndChar) || IsPathDiv(EndChar); wchar CmdChar=toupperw(*Command); bool Add=wcschr(L"AFUM",CmdChar)!=NULL; bool Extract=CmdChar=='X' || CmdChar=='E'; if (EndSeparator && !Add) wcsncpyz(ExtrPath,Arg,ASIZE(ExtrPath)); else if ((Add || CmdChar=='T') && (*Arg!='@' || ListMode==RCLM_REJECT_LISTS)) FileArgs.AddString(Arg); else { FindData FileData; bool Found=FindFile::FastFind(Arg,&FileData); if ((!Found || ListMode==RCLM_ACCEPT_LISTS) && ListMode!=RCLM_REJECT_LISTS && *Arg=='@' && !IsWildcard(Arg)) { FileLists=true; ReadTextFile(Arg+1,&FileArgs,false,true,FilelistCharset,true,true,true); } else if (Found && FileData.IsDir && Extract && *ExtrPath==0) { wcsncpyz(ExtrPath,Arg,ASIZE(ExtrPath)); AddEndSlash(ExtrPath,ASIZE(ExtrPath)); } else FileArgs.AddString(Arg); } } }
void CommandData::ProcessSwitch(const wchar *Switch) { switch(toupperw(Switch[0])) { case '@': ListMode=Switch[1]=='+' ? RCLM_ACCEPT_LISTS:RCLM_REJECT_LISTS; break; case 'A': switch(toupperw(Switch[1])) { case 'C': ClearArc=true; break; case 'D': AppendArcNameToPath=true; break; #ifndef SFX_MODULE case 'G': if (Switch[2]=='-' && Switch[3]==0) GenerateArcName=0; else { GenerateArcName=true; wcsncpyz(GenerateMask,Switch+2,ASIZE(GenerateMask)); } break; #endif case 'I': IgnoreGeneralAttr=true; break; case 'N': // Reserved for archive name. break; case 'O': AddArcOnly=true; break; case 'P': wcscpy(ArcPath,Switch+2); break; case 'S': SyncFiles=true; break; default: BadSwitch(Switch); break; } break; case 'C': if (Switch[2]==0) switch(toupperw(Switch[1])) { case '-': DisableComment=true; break; case 'U': ConvertNames=NAMES_UPPERCASE; break; case 'L': ConvertNames=NAMES_LOWERCASE; break; } break; case 'D': if (Switch[2]==0) switch(toupperw(Switch[1])) { case 'S': DisableSortSolid=true; break; case 'H': OpenShared=true; break; case 'F': DeleteFiles=true; break; } break; case 'E': switch(toupperw(Switch[1])) { case 'P': switch(Switch[2]) { case 0: ExclPath=EXCL_SKIPWHOLEPATH; break; case '1': ExclPath=EXCL_BASEPATH; break; case '2': ExclPath=EXCL_SAVEFULLPATH; break; case '3': ExclPath=EXCL_ABSPATH; break; } break; default: if (Switch[1]=='+') { InclFileAttr|=GetExclAttr(Switch+2); InclAttrSet=true; } else ExclFileAttr|=GetExclAttr(Switch+1); break; } break; case 'F': if (Switch[1]==0) FreshFiles=true; else BadSwitch(Switch); break; case 'H': switch (toupperw(Switch[1])) { case 'P': EncryptHeaders=true; if (Switch[2]!=0) { Password.Set(Switch+2); cleandata((void *)Switch,wcslen(Switch)*sizeof(Switch[0])); } else if (!Password.IsSet()) { uiGetPassword(UIPASSWORD_GLOBAL,NULL,&Password); eprintf(L"\n"); } break; default : BadSwitch(Switch); break; } break; case 'I': if (wcsnicomp(Switch+1,L"LOG",3)==0) { wcsncpyz(LogName,Switch[4]!=0 ? Switch+4:DefLogName,ASIZE(LogName)); break; } if (wcsicomp(Switch+1,L"SND")==0) { Sound=true; break; } if (wcsicomp(Switch+1,L"ERR")==0) { MsgStream=MSG_STDERR; // Set it immediately when parsing the command line, so it also // affects messages issued while parsing the command line. SetConsoleMsgStream(MSG_STDERR); break; } if (wcsnicomp(Switch+1,L"EML",3)==0) { wcsncpyz(EmailTo,Switch[4]!=0 ? Switch+4:L"@",ASIZE(EmailTo)); break; } if (wcsicomp(Switch+1,L"M")==0) { MoreInfo=true; break; } if (wcsicomp(Switch+1,L"NUL")==0) { MsgStream=MSG_NULL; SetConsoleMsgStream(MSG_NULL); break; } if (toupperw(Switch[1])=='D') { for (uint I=2;Switch[I]!=0;I++) switch(toupperw(Switch[I])) { case 'Q': MsgStream=MSG_ERRONLY; SetConsoleMsgStream(MSG_ERRONLY); break; case 'C': DisableCopyright=true; break; case 'D': DisableDone=true; break; case 'P': DisablePercentage=true; break; } break; } if (wcsnicomp(Switch+1,L"OFF",3)==0) { switch(Switch[4]) { case 0: case '1': Shutdown=POWERMODE_OFF; break; case '2': Shutdown=POWERMODE_HIBERNATE; break; case '3': Shutdown=POWERMODE_SLEEP; break; case '4': Shutdown=POWERMODE_RESTART; break; } break; } if (wcsicomp(Switch+1,L"VER")==0) { PrintVersion=true; break; } break; case 'K': switch(toupperw(Switch[1])) { case 'B': KeepBroken=true; break; case 0: Lock=true; break; } break; case 'M': switch(toupperw(Switch[1])) { case 'C': { const wchar *Str=Switch+2; if (*Str=='-') for (uint I=0;I<ASIZE(FilterModes);I++) FilterModes[I].State=FILTER_DISABLE; else while (*Str!=0) { int Param1=0,Param2=0; FilterState State=FILTER_AUTO; FilterType Type=FILTER_NONE; if (IsDigit(*Str)) { Param1=atoiw(Str); while (IsDigit(*Str)) Str++; } if (*Str==':' && IsDigit(Str[1])) { Param2=atoiw(++Str); while (IsDigit(*Str)) Str++; } switch(toupperw(*(Str++))) { case 'T': Type=FILTER_PPM; break; case 'E': Type=FILTER_E8; break; case 'D': Type=FILTER_DELTA; break; case 'A': Type=FILTER_AUDIO; break; case 'C': Type=FILTER_RGB; break; case 'I': Type=FILTER_ITANIUM; break; case 'R': Type=FILTER_ARM; break; } if (*Str=='+' || *Str=='-') State=*(Str++)=='+' ? FILTER_FORCE:FILTER_DISABLE; FilterModes[Type].State=State; FilterModes[Type].Param1=Param1; FilterModes[Type].Param2=Param2; } } break; case 'M': break; case 'D': break; case 'S': { wchar StoreNames[1024]; wcsncpyz(StoreNames,(Switch[2]==0 ? DefaultStoreList:Switch+2),ASIZE(StoreNames)); wchar *Names=StoreNames; while (*Names!=0) { wchar *End=wcschr(Names,';'); if (End!=NULL) *End=0; if (*Names=='.') Names++; wchar Mask[NM]; if (wcspbrk(Names,L"*?.")==NULL) swprintf(Mask,ASIZE(Mask),L"*.%ls",Names); else wcsncpyz(Mask,Names,ASIZE(Mask)); StoreArgs.AddString(Mask); if (End==NULL) break; Names=End+1; } } break; #ifdef RAR_SMP case 'T': Threads=atoiw(Switch+2); if (Threads>MaxPoolThreads || Threads<1) BadSwitch(Switch); else { } break; #endif default: Method=Switch[1]-'0'; if (Method>5 || Method<0) BadSwitch(Switch); break; } break; case 'N': case 'X': if (Switch[1]!=0) { StringList *Args=toupperw(Switch[0])=='N' ? &InclArgs:&ExclArgs; if (Switch[1]=='@' && !IsWildcard(Switch)) ReadTextFile(Switch+2,Args,false,true,FilelistCharset,true,true,true); else Args->AddString(Switch+1); } break; case 'O': switch(toupperw(Switch[1])) { case '+': Overwrite=OVERWRITE_ALL; break; case '-': Overwrite=OVERWRITE_NONE; break; case 0: Overwrite=OVERWRITE_FORCE_ASK; break; #ifdef _WIN_ALL case 'C': SetCompressedAttr=true; break; #endif case 'H': SaveHardLinks=true; break; #ifdef SAVE_LINKS case 'L': SaveSymLinks=true; if (toupperw(Switch[2])=='A') AbsoluteLinks=true; break; #endif #ifdef _WIN_ALL case 'N': if (toupperw(Switch[2])=='I') AllowIncompatNames=true; break; #endif case 'R': Overwrite=OVERWRITE_AUTORENAME; break; #ifdef _WIN_ALL case 'S': SaveStreams=true; break; #endif case 'W': ProcessOwners=true; break; default : BadSwitch(Switch); break; } break; case 'P': if (Switch[1]==0) { uiGetPassword(UIPASSWORD_GLOBAL,NULL,&Password); eprintf(L"\n"); } else { Password.Set(Switch+1); cleandata((void *)Switch,wcslen(Switch)*sizeof(Switch[0])); } break; #ifndef SFX_MODULE case 'Q': if (toupperw(Switch[1])=='O') switch(toupperw(Switch[2])) { case 0: QOpenMode=QOPEN_AUTO; break; case '-': QOpenMode=QOPEN_NONE; break; case '+': QOpenMode=QOPEN_ALWAYS; break; default: BadSwitch(Switch); break; } else BadSwitch(Switch); break; #endif case 'R': switch(toupperw(Switch[1])) { case 0: Recurse=RECURSE_ALWAYS; break; case '-': Recurse=RECURSE_DISABLE; break; case '0': Recurse=RECURSE_WILDCARDS; break; case 'I': { Priority=atoiw(Switch+2); if (Priority<0 || Priority>15) BadSwitch(Switch); const wchar *ChPtr=wcschr(Switch+2,':'); if (ChPtr!=NULL) { SleepTime=atoiw(ChPtr+1); if (SleepTime>1000) BadSwitch(Switch); InitSystemOptions(SleepTime); } SetPriority(Priority); } break; } break; case 'S': if (IsDigit(Switch[1])) { Solid|=SOLID_COUNT; SolidCount=atoiw(&Switch[1]); } else switch(toupperw(Switch[1])) { case 0: Solid|=SOLID_NORMAL; break; case '-': Solid=SOLID_NONE; break; case 'E': Solid|=SOLID_FILEEXT; break; case 'V': Solid|=Switch[2]=='-' ? SOLID_VOLUME_DEPENDENT:SOLID_VOLUME_INDEPENDENT; break; case 'D': Solid|=SOLID_VOLUME_DEPENDENT; break; case 'L': if (IsDigit(Switch[2])) FileSizeLess=atoilw(Switch+2); break; case 'M': if (IsDigit(Switch[2])) FileSizeMore=atoilw(Switch+2); break; case 'C': { bool AlreadyBad=false; // Avoid reporting "bad switch" several times. RAR_CHARSET rch=RCH_DEFAULT; switch(toupperw(Switch[2])) { case 'A': rch=RCH_ANSI; break; case 'O': rch=RCH_OEM; break; case 'U': rch=RCH_UNICODE; break; case 'F': rch=RCH_UTF8; break; default : BadSwitch(Switch); AlreadyBad=true; break; }; if (!AlreadyBad) if (Switch[3]==0) CommentCharset=FilelistCharset=ErrlogCharset=RedirectCharset=rch; else for (uint I=3;Switch[I]!=0 && !AlreadyBad;I++) switch(toupperw(Switch[I])) { case 'C': CommentCharset=rch; break; case 'L': FilelistCharset=rch; break; case 'R': RedirectCharset=rch; break; default: BadSwitch(Switch); AlreadyBad=true; break; } // Set it immediately when parsing the command line, so it also // affects messages issued while parsing the command line. SetConsoleRedirectCharset(RedirectCharset); } break; } break; case 'T': switch(toupperw(Switch[1])) { case 'K': ArcTime=ARCTIME_KEEP; break; case 'L': ArcTime=ARCTIME_LATEST; break; case 'O': FileTimeBefore.SetAgeText(Switch+2); break; case 'N': FileTimeAfter.SetAgeText(Switch+2); break; case 'B': FileTimeBefore.SetIsoText(Switch+2); break; case 'A': FileTimeAfter.SetIsoText(Switch+2); break; case 'S': { EXTTIME_MODE Mode=EXTTIME_HIGH3; bool CommonMode=Switch[2]>='0' && Switch[2]<='4'; if (CommonMode) Mode=(EXTTIME_MODE)(Switch[2]-'0'); if (Mode==EXTTIME_HIGH1 || Mode==EXTTIME_HIGH2) // '2' and '3' not supported anymore. Mode=EXTTIME_HIGH3; if (Switch[2]=='-') Mode=EXTTIME_NONE; if (CommonMode || Switch[2]=='-' || Switch[2]=='+' || Switch[2]==0) xmtime=xctime=xatime=Mode; else { if (Switch[3]>='0' && Switch[3]<='4') Mode=(EXTTIME_MODE)(Switch[3]-'0'); if (Mode==EXTTIME_HIGH1 || Mode==EXTTIME_HIGH2) // '2' and '3' not supported anymore. Mode=EXTTIME_HIGH3; if (Switch[3]=='-') Mode=EXTTIME_NONE; switch(toupperw(Switch[2])) { case 'M': xmtime=Mode; break; case 'C': xctime=Mode; break; case 'A': xatime=Mode; break; } } } break; case '-': Test=false; break; case 0: Test=true; break; default: BadSwitch(Switch); break; } break; case 'U': if (Switch[1]==0) UpdateFiles=true; else BadSwitch(Switch); break; case 'V': switch(toupperw(Switch[1])) { case 'P': VolumePause=true; break; case 'E': if (toupperw(Switch[2])=='R') VersionControl=atoiw(Switch+3)+1; break; case '-': VolSize=0; break; default: VolSize=VOLSIZE_AUTO; // UnRAR -v switch for list command. break; } break; case 'W': wcsncpyz(TempPath,Switch+1,ASIZE(TempPath)); AddEndSlash(TempPath,ASIZE(TempPath)); break; case 'Y': AllYes=true; break; case 'Z': if (Switch[1]==0) { // If comment file is not specified, we read data from stdin. wcscpy(CommentFile,L"stdin"); } else wcsncpyz(CommentFile,Switch+1,ASIZE(CommentFile)); break; case '?' : OutHelp(RARX_SUCCESS); break; default : BadSwitch(Switch); break; } }
// Unicode version of etoupper. wchar etoupperw(wchar ch) { if (ch=='i') return('I'); return(toupperw(ch)); }
static void GenArcName(wchar *ArcName,const wchar *GenerateMask,uint ArcNumber,bool &ArcNumPresent) { bool Prefix=false; if (*GenerateMask=='+') { Prefix=true; // Add the time string before the archive name. GenerateMask++; // Skip '+' in the beginning of time mask. } wchar Mask[MAX_GENERATE_MASK]; wcsncpyz(Mask,*GenerateMask!=0 ? GenerateMask:L"yyyymmddhhmmss",ASIZE(Mask)); bool QuoteMode=false,Hours=false; for (uint I=0;Mask[I]!=0;I++) { if (Mask[I]=='{' || Mask[I]=='}') { QuoteMode=(Mask[I]=='{'); continue; } if (QuoteMode) continue; int CurChar=toupperw(Mask[I]); if (CurChar=='H') Hours=true; if (Hours && CurChar=='M') { // Replace minutes with 'I'. We use 'M' both for months and minutes, // so we treat as minutes only those 'M' which are found after hours. Mask[I]='I'; } if (CurChar=='N') { uint Digits=GetDigits(ArcNumber); uint NCount=0; while (toupperw(Mask[I+NCount])=='N') NCount++; // Here we ensure that we have enough 'N' characters to fit all digits // of archive number. We'll replace them by actual number later // in this function. if (NCount<Digits) { wmemmove(Mask+I+Digits,Mask+I+NCount,wcslen(Mask+I+NCount)+1); wmemset(Mask+I,'N',Digits); } I+=Max(Digits,NCount)-1; ArcNumPresent=true; continue; } } RarTime CurTime; CurTime.SetCurrentTime(); RarLocalTime rlt; CurTime.GetLocal(&rlt); wchar Ext[NM],*Dot=GetExt(ArcName); *Ext=0; if (Dot==NULL) wcscpy(Ext,*PointToName(ArcName)==0 ? L".rar":L""); else { wcsncpyz(Ext,Dot,ASIZE(Ext)); *Dot=0; } int WeekDay=rlt.wDay==0 ? 6:rlt.wDay-1; int StartWeekDay=rlt.yDay-WeekDay; if (StartWeekDay<0) if (StartWeekDay<=-4) StartWeekDay+=IsLeapYear(rlt.Year-1) ? 366:365; else StartWeekDay=0; int CurWeek=StartWeekDay/7+1; if (StartWeekDay%7>=4) CurWeek++; char Field[10][6]; sprintf(Field[0],"%04d",rlt.Year); sprintf(Field[1],"%02d",rlt.Month); sprintf(Field[2],"%02d",rlt.Day); sprintf(Field[3],"%02d",rlt.Hour); sprintf(Field[4],"%02d",rlt.Minute); sprintf(Field[5],"%02d",rlt.Second); sprintf(Field[6],"%02d",CurWeek); sprintf(Field[7],"%d",WeekDay+1); sprintf(Field[8],"%03d",rlt.yDay+1); sprintf(Field[9],"%05d",ArcNumber); const wchar *MaskChars=L"YMDHISWAEN"; int CField[sizeof(Field)/sizeof(Field[0])]; memset(CField,0,sizeof(CField)); QuoteMode=false; for (int I=0;Mask[I]!=0;I++) { if (Mask[I]=='{' || Mask[I]=='}') { QuoteMode=(Mask[I]=='{'); continue; } if (QuoteMode) continue; const wchar *ChPtr=wcschr(MaskChars,toupperw(Mask[I])); if (ChPtr!=NULL) CField[ChPtr-MaskChars]++; } wchar DateText[MAX_GENERATE_MASK]; *DateText=0; QuoteMode=false; for (size_t I=0,J=0;Mask[I]!=0 && J<ASIZE(DateText)-1;I++) { if (Mask[I]=='{' || Mask[I]=='}') { QuoteMode=(Mask[I]=='{'); continue; } const wchar *ChPtr=wcschr(MaskChars,toupperw(Mask[I])); if (ChPtr==NULL || QuoteMode) { DateText[J]=Mask[I]; #ifdef _WIN_ALL // We do not allow ':' in Windows because of NTFS streams. // Users had problems after specifying hh:mm mask. if (DateText[J]==':') DateText[J]='_'; #endif } else { size_t FieldPos=ChPtr-MaskChars; int CharPos=(int)strlen(Field[FieldPos])-CField[FieldPos]--; if (FieldPos==1 && toupperw(Mask[I+1])=='M' && toupperw(Mask[I+2])=='M') { wcsncpyz(DateText+J,GetMonthName(rlt.Month-1),ASIZE(DateText)-J); J=wcslen(DateText); I+=2; continue; } if (CharPos<0) DateText[J]=Mask[I]; else DateText[J]=Field[FieldPos][CharPos]; } DateText[++J]=0; } if (Prefix) { wchar NewName[NM]; GetFilePath(ArcName,NewName,ASIZE(NewName)); AddEndSlash(NewName,ASIZE(NewName)); wcsncatz(NewName,DateText,ASIZE(NewName)); wcsncatz(NewName,PointToName(ArcName),ASIZE(NewName)); wcscpy(ArcName,NewName); } else wcscat(ArcName,DateText); wcscat(ArcName,Ext); }
// Unicode version of etoupper. wchar etoupperw(wchar ch) { if (ch=='i') return 'I'; return toupperw(ch); }