xref: /reactos/base/shell/cmd/prompt.c (revision 190b3da9)
1 /*
2  *  PROMPT.C - prompt handling.
3  *
4  *
5  *  History:
6  *
7  *    14/01/95 (Tim Normal)
8  *        started.
9  *
10  *    08/08/95 (Matt Rains)
11  *        i have cleaned up the source code. changes now bring this source
12  *        into guidelines for recommended programming practice.
13  *
14  *    01/06/96 (Tim Norman)
15  *        added day of the week printing (oops, forgot about that!)
16  *
17  *    08/07/96 (Steffan Kaiser)
18  *        small changes for speed
19  *
20  *    20-Jul-1998 (John P Price <linux-guru@gcfl.net>)
21  *        removed redundant day strings. Use ones defined in date.c.
22  *
23  *    27-Jul-1998 (John P Price <linux-guru@gcfl.net>)
24  *        added config.h include
25  *
26  *    28-Jul-1998 (John P Price <linux-guru@gcfl.net>)
27  *        moved cmd_prompt from internal.c to here
28  *
29  *    09-Dec-1998 (Eric Kohl)
30  *        Added help text ("/?").
31  *
32  *    14-Dec-1998 (Eric Kohl)
33  *        Added "$+" option.
34  *
35  *    09-Jan-1999 (Eric Kohl)
36  *        Added "$A", "$C" and "$F" option.
37  *        Added locale support.
38  *        Fixed "$V" option.
39  *
40  *    20-Jan-1999 (Eric Kohl)
41  *        Unicode and redirection safe!
42  *
43  *    24-Jan-1999 (Eric Kohl)
44  *        Fixed Win32 environment handling.
45  *
46  *    30-Apr-2005 (Magnus Olsen <magnus@greatlord.com>)
47  *        Remove all hardcoded strings in En.rc
48  */
49 #include "precomp.h"
50 
51 /* The default prompt */
52 static TCHAR DefaultPrompt[] = _T("$P$G");
53 
54 /*
55  * Initialize prompt support.
56  */
InitPrompt(VOID)57 VOID InitPrompt(VOID)
58 {
59     TCHAR Buffer[2];
60 
61     /*
62      * Set the PROMPT environment variable if it doesn't exist already.
63      * You can change the PROMPT environment variable before cmd starts.
64      */
65     if (GetEnvironmentVariable(_T("PROMPT"), Buffer, _countof(Buffer)) == 0)
66         SetEnvironmentVariable(_T("PROMPT"), DefaultPrompt);
67 }
68 
69 /*
70  * Checks if information line should be displayed.
71  */
HasInfoLine(VOID)72 BOOL HasInfoLine(VOID)
73 {
74     LPTSTR pr;
75     TCHAR szPrompt[256];
76 
77     if (GetEnvironmentVariable(_T("PROMPT"), szPrompt, _countof(szPrompt)))
78     {
79         pr = szPrompt;
80         while (*pr)
81         {
82             if (*pr++ != _T('$'))
83                 continue;
84             if (!*pr || _totupper(*pr++) != _T('I'))
85                 continue;
86 
87             return TRUE;
88         }
89     }
90 
91     return FALSE;
92 }
93 
94 /*
95  * Print an information line on top of the screen.
96  */
PrintInfoLine(VOID)97 VOID PrintInfoLine(VOID)
98 {
99 #define FOREGROUND_WHITE (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY)
100 
101     HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
102     CONSOLE_SCREEN_BUFFER_INFO csbi;
103     COORD coPos;
104     DWORD dwWritten;
105 
106     PTSTR pszInfoLine = NULL;
107     INT iInfoLineLen;
108 
109     /* Return directly if the output handle is not a console handle */
110     if (!GetConsoleScreenBufferInfo(hOutput, &csbi))
111         return;
112 
113     iInfoLineLen = LoadString(CMD_ModuleHandle, STRING_CMD_INFOLINE, (PTSTR)&pszInfoLine, 0);
114     if (!pszInfoLine || iInfoLineLen == 0)
115         return;
116 
117     /* Display the localized information line */
118     coPos.X = 0;
119     coPos.Y = 0;
120     FillConsoleOutputAttribute(hOutput, BACKGROUND_BLUE | FOREGROUND_WHITE,
121                                csbi.dwSize.X,
122                                coPos, &dwWritten);
123     FillConsoleOutputCharacter(hOutput, _T(' '),
124                                csbi.dwSize.X,
125                                coPos, &dwWritten);
126 
127     WriteConsoleOutputCharacter(hOutput, pszInfoLine, iInfoLineLen,
128                                 coPos, &dwWritten);
129 }
130 
131 /*
132  * Print the command-line prompt.
133  */
PrintPrompt(VOID)134 VOID PrintPrompt(VOID)
135 {
136     LPTSTR pr, Prompt;
137     TCHAR szPrompt[256];
138     TCHAR szPath[MAX_PATH];
139 
140     if (GetEnvironmentVariable(_T("PROMPT"), szPrompt, _countof(szPrompt)))
141         Prompt = szPrompt;
142     else
143         Prompt = DefaultPrompt;
144 
145     /*
146      * Special pre-handling for $I: If the information line is displayed
147      * on top of the screen, ensure that the prompt won't be hidden below it.
148      */
149     if (HasInfoLine() && GetCursorY() == 0)
150         ConOutChar(_T('\n'));
151 
152     /* Parse the prompt string */
153     for (pr = Prompt; *pr; ++pr)
154     {
155         if (*pr != _T('$'))
156         {
157             ConOutChar(*pr);
158         }
159         else
160         {
161             ++pr;
162             if (!*pr) break;
163             switch (_totupper(*pr))
164             {
165                 case _T('A'):
166                     ConOutChar(_T('&'));
167                     break;
168 
169                 case _T('B'):
170                     ConOutChar(_T('|'));
171                     break;
172 
173                 case _T('C'):
174                     ConOutChar(_T('('));
175                     break;
176 
177                 case _T('D'):
178                     ConOutPrintf(_T("%s"), GetDateString());
179                     break;
180 
181                 case _T('E'):
182                     ConOutChar(_T('\x1B'));
183                     break;
184 
185                 case _T('F'):
186                     ConOutChar(_T(')'));
187                     break;
188 
189                 case _T('G'):
190                     ConOutChar(_T('>'));
191                     break;
192 
193                 case _T('H'):
194                     ConOutPuts(_T("\x08 \x08"));
195                     break;
196 
197                 case _T('I'):
198                     PrintInfoLine();
199                     break;
200 
201                 case _T('L'):
202                     ConOutChar(_T('<'));
203                     break;
204 
205                 case _T('N'):
206                 {
207                     GetCurrentDirectory(_countof(szPath), szPath);
208                     ConOutChar(szPath[0]);
209                     break;
210                 }
211 
212                 case _T('P'):
213                 {
214                     GetCurrentDirectory(_countof(szPath), szPath);
215                     ConOutPrintf(_T("%s"), szPath);
216                     break;
217                 }
218 
219                 case _T('Q'):
220                     ConOutChar(_T('='));
221                     break;
222 
223                 case _T('S'):
224                     ConOutChar(_T(' '));
225                     break;
226 
227                 case _T('T'):
228                     ConOutPrintf(_T("%s"), GetTimeString());
229                     break;
230 
231                 case _T('V'):
232                     PrintOSVersion();
233                     break;
234 
235                 case _T('_'):
236                     ConOutChar(_T('\n'));
237                     break;
238 
239                 case _T('$'):
240                     ConOutChar(_T('$'));
241                     break;
242 
243 #ifdef FEATURE_DIRECTORY_STACK
244                 case _T('+'):
245                 {
246                     INT i;
247                     for (i = 0; i < GetDirectoryStackDepth(); i++)
248                         ConOutChar(_T('+'));
249                     break;
250                 }
251 #endif
252             }
253         }
254     }
255 }
256 
257 
258 #ifdef INCLUDE_CMD_PROMPT
259 
cmd_prompt(LPTSTR param)260 INT cmd_prompt(LPTSTR param)
261 {
262     INT retval = 0;
263 
264     if (!_tcsncmp(param, _T("/?"), 2))
265     {
266         ConOutResPaging(TRUE, STRING_PROMPT_HELP1);
267 #ifdef FEATURE_DIRECTORY_STACK
268         ConOutResPaging(FALSE, STRING_PROMPT_HELP2);
269 #endif
270         ConOutResPaging(FALSE, STRING_PROMPT_HELP3);
271         return 0;
272     }
273 
274     /*
275      * Set the PROMPT environment variable. If 'param' is NULL or is
276      * an empty string (the user entered "prompt" only), then remove
277      * the environment variable and therefore use the default prompt.
278      * Otherwise, use the new prompt.
279      */
280     if (!SetEnvironmentVariable(_T("PROMPT"),
281                                 (param && param[0] != _T('\0') ? param : NULL)))
282     {
283         retval = 1;
284     }
285 
286     if (BatType != CMD_TYPE)
287     {
288         if (retval != 0)
289             nErrorLevel = retval;
290     }
291     else
292     {
293         nErrorLevel = retval;
294     }
295 
296     return retval;
297 }
298 #endif
299 
300 /* EOF */
301