update for HEAD-2003050101
[reactos.git] / subsys / system / cmd / dirstack.c
1 /*
2  *  DIRSTACK.C - pushd / pop (directory stack) internal commands.
3  *
4  *
5  *  History:
6  *
7  *    14-Dec-1998 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
8  *        Implemented PUSHD and POPD command.
9  *
10  *    20-Jan-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
11  *        Unicode and redirection safe!
12  *
13  *    20-Jan-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
14  *        Added DIRS command.
15  */
16
17 #include "config.h"
18
19 #ifdef FEATURE_DIRECTORY_STACK
20
21 #include <windows.h>
22 #include <tchar.h>
23 #include <string.h>
24 #include <stdlib.h>
25
26 #include "cmd.h"
27
28
29 typedef struct tagDIRENTRY
30 {
31         struct tagDIRENTRY *prev;
32         struct tagDIRENTRY *next;
33         LPTSTR pszPath;
34 } DIRENTRY, *LPDIRENTRY;
35
36
37 static INT nStackDepth;
38 static LPDIRENTRY lpStackTop;
39 static LPDIRENTRY lpStackBottom;
40
41
42 static INT
43 PushDirectory (LPTSTR pszPath)
44 {
45         LPDIRENTRY lpDir;
46
47         lpDir = (LPDIRENTRY)malloc (sizeof (DIRENTRY));
48         if (!lpDir)
49         {
50                 error_out_of_memory ();
51                 return -1;
52         }
53
54         lpDir->prev = NULL;
55         if (lpStackTop == NULL)
56         {
57                 lpDir->next = NULL;
58                 lpStackBottom = lpDir;
59         }
60         else
61         {
62                 lpDir->next = lpStackTop;
63                 lpStackTop->prev = lpDir;
64         }
65         lpStackTop = lpDir;
66
67         lpDir->pszPath = (LPTSTR)malloc ((_tcslen(pszPath)+1)*sizeof(TCHAR));
68         if (!lpDir->pszPath)
69         {
70                 free (lpDir);
71                 error_out_of_memory ();
72                 return -1;
73         }
74
75         _tcscpy (lpDir->pszPath, pszPath);
76
77         nStackDepth++;
78
79         return 0;
80 }
81
82
83 static VOID
84 PopDirectory (VOID)
85 {
86         LPDIRENTRY lpDir;
87
88         if (nStackDepth == 0)
89                 return;
90
91         lpDir = lpStackTop;
92         lpStackTop = lpDir->next;
93         if (lpStackTop != NULL)
94                 lpStackTop->prev = NULL;
95         else
96                 lpStackBottom = NULL;
97
98         free (lpDir->pszPath);
99         free (lpDir);
100
101         nStackDepth--;
102 }
103
104
105 static VOID
106 GetDirectoryStackTop (LPTSTR pszPath)
107 {
108         if (lpStackTop)
109                 _tcsncpy (pszPath, lpStackTop->pszPath, MAX_PATH);
110         else
111                 *pszPath = _T('\0');
112 }
113
114
115 /*
116  * initialize directory stack
117  */
118 VOID InitDirectoryStack (VOID)
119 {
120         nStackDepth = 0;
121         lpStackTop = NULL;
122         lpStackBottom = NULL;
123 }
124
125
126 /*
127  * destroy directory stack
128  */
129 VOID DestroyDirectoryStack (VOID)
130 {
131         while (nStackDepth)
132                 PopDirectory ();
133 }
134
135
136 INT GetDirectoryStackDepth (VOID)
137 {
138         return nStackDepth;
139 }
140
141
142 /*
143  * pushd command
144  */
145 INT CommandPushd (LPTSTR first, LPTSTR rest)
146 {
147         TCHAR curPath[MAX_PATH];
148         TCHAR newPath[MAX_PATH];
149         BOOL  bChangePath = FALSE;
150
151         if (!_tcsncmp (rest, _T("/?"), 2))
152         {
153                 ConOutPuts (_T("Stores the current directory for use by the POPD command, then\n"
154                                "changes to the specified directory.\n\n"
155                                "PUSHD [path | ..]\n\n"
156                                "  path        Specifies the directory to make the current directory"));
157                 return 0;
158         }
159
160         if (rest[0] != _T('\0'))
161         {
162                 GetFullPathName (rest, MAX_PATH, newPath, NULL);
163                 bChangePath = IsValidPathName (newPath);
164         }
165
166         GetCurrentDirectory (MAX_PATH, curPath);
167         if (PushDirectory (curPath))
168                 return 0;
169
170         if (bChangePath)
171                 SetCurrentDirectory (newPath);
172
173         return 0;
174 }
175
176
177 /*
178  * popd command
179  */
180 INT CommandPopd (LPTSTR first, LPTSTR rest)
181 {
182         TCHAR szPath[MAX_PATH];
183
184         if (!_tcsncmp(rest, _T("/?"), 2))
185         {
186                 ConOutPuts (_T("Changes to the directory stored by the PUSHD command.\n\n"
187                                "POPD"));
188                 return 0;
189         }
190
191         if (GetDirectoryStackDepth () == 0)
192                 return 0;
193
194         GetDirectoryStackTop (szPath);
195         PopDirectory ();
196
197         SetCurrentDirectory (szPath);
198
199         return 0;
200 }
201
202
203 /*
204  * dirs command
205  */
206 INT CommandDirs (LPTSTR first, LPTSTR rest)
207 {
208         LPDIRENTRY lpDir;
209
210         if (!_tcsncmp(rest, _T("/?"), 2))
211         {
212                 ConOutPuts (_T("Prints the contents of the directory stack.\n"
213                                "\n"
214                                "DIRS"));
215                 return 0;
216         }
217
218
219         lpDir = lpStackBottom;
220
221         if (lpDir == NULL)
222         {
223                 ConOutPuts (_T("Directory stack empty"));
224                 return 0;
225         }
226
227         while (lpDir != NULL)
228         {
229                 ConOutPuts (lpDir->pszPath);
230
231                 lpDir = lpDir->prev;
232         }
233
234         return 0;
235 }
236
237 #endif /* FEATURE_DIRECTORY_STACK */