7ad044c1c6636a8f98d8f870ba308b84660af4b6
[reactos.git] / base / setup / usetup / partlist.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2002, 2003, 2004, 2005 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /* COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS text-mode setup
21 * FILE: base/setup/usetup/partlist.c
22 * PURPOSE: Partition list functions
23 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
24 */
25
26 #include "usetup.h"
27
28 #define NDEBUG
29 #include <debug.h>
30
31 /* HELPERS FOR PARTITION TYPES **********************************************/
32
33 VOID
34 GetPartTypeStringFromPartitionType(
35 IN UCHAR partitionType,
36 OUT PCHAR strPartType,
37 IN ULONG cchPartType)
38 {
39 /* Determine partition type */
40
41 if (IsContainerPartition(partitionType))
42 {
43 RtlStringCchCopyA(strPartType, cchPartType, MUIGetString(STRING_EXTENDED_PARTITION));
44 }
45 else if (partitionType == PARTITION_ENTRY_UNUSED)
46 {
47 RtlStringCchCopyA(strPartType, cchPartType, MUIGetString(STRING_FORMATUNUSED));
48 }
49 else
50 {
51 UINT i;
52
53 /* Do the table lookup */
54 for (i = 0; i < ARRAYSIZE(PartitionTypes); i++)
55 {
56 if (partitionType == PartitionTypes[i].Type)
57 {
58 RtlStringCchCopyA(strPartType, cchPartType, PartitionTypes[i].Description);
59 return;
60 }
61 }
62
63 /* We are here because the partition type is unknown */
64 RtlStringCchCopyA(strPartType, cchPartType, MUIGetString(STRING_FORMATUNKNOWN));
65 }
66 }
67
68
69 /* FUNCTIONS ****************************************************************/
70
71 VOID
72 InitPartitionListUi(
73 IN OUT PPARTLIST_UI ListUi,
74 IN PPARTLIST List,
75 IN SHORT Left,
76 IN SHORT Top,
77 IN SHORT Right,
78 IN SHORT Bottom)
79 {
80 ListUi->List = List;
81 // ListUi->FirstShown = NULL;
82 // ListUi->LastShown = NULL;
83
84 ListUi->Left = Left;
85 ListUi->Top = Top;
86 ListUi->Right = Right;
87 ListUi->Bottom = Bottom;
88
89 ListUi->Line = 0;
90 ListUi->Offset = 0;
91
92 // ListUi->Redraw = TRUE;
93 }
94
95 static
96 VOID
97 PrintEmptyLine(
98 IN PPARTLIST_UI ListUi)
99 {
100 COORD coPos;
101 ULONG Written;
102 USHORT Width;
103 USHORT Height;
104
105 Width = ListUi->Right - ListUi->Left - 1;
106 Height = ListUi->Bottom - ListUi->Top - 2;
107
108 coPos.X = ListUi->Left + 1;
109 coPos.Y = ListUi->Top + 1 + ListUi->Line;
110
111 if (ListUi->Line >= 0 && ListUi->Line <= Height)
112 {
113 FillConsoleOutputAttribute(StdOutput,
114 FOREGROUND_WHITE | BACKGROUND_BLUE,
115 Width,
116 coPos,
117 &Written);
118
119 FillConsoleOutputCharacterA(StdOutput,
120 ' ',
121 Width,
122 coPos,
123 &Written);
124 }
125
126 ListUi->Line++;
127 }
128
129 static
130 VOID
131 PrintPartitionData(
132 IN PPARTLIST_UI ListUi,
133 IN PDISKENTRY DiskEntry,
134 IN PPARTENTRY PartEntry)
135 {
136 PPARTLIST List = ListUi->List;
137 CHAR LineBuffer[128];
138 COORD coPos;
139 ULONG Written;
140 USHORT Width;
141 USHORT Height;
142 LARGE_INTEGER PartSize;
143 PCHAR Unit;
144 UCHAR Attribute;
145 CHAR PartTypeString[32];
146 PCHAR PartType = PartTypeString;
147
148 Width = ListUi->Right - ListUi->Left - 1;
149 Height = ListUi->Bottom - ListUi->Top - 2;
150
151 coPos.X = ListUi->Left + 1;
152 coPos.Y = ListUi->Top + 1 + ListUi->Line;
153
154 /* Get the partition size */
155 PartSize.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
156 #if 0
157 if (PartSize.QuadPart >= 10 * GB) /* 10 GB */
158 {
159 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, GB);
160 Unit = MUIGetString(STRING_GB);
161 }
162 else
163 #endif
164 if (PartSize.QuadPart >= 10 * MB) /* 10 MB */
165 {
166 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, MB);
167 Unit = MUIGetString(STRING_MB);
168 }
169 else
170 {
171 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, KB);
172 Unit = MUIGetString(STRING_KB);
173 }
174
175 if (PartEntry->IsPartitioned == FALSE)
176 {
177 sprintf(LineBuffer,
178 MUIGetString(STRING_UNPSPACE),
179 PartEntry->LogicalPartition ? " " : "",
180 PartEntry->LogicalPartition ? "" : " ",
181 PartSize.u.LowPart,
182 Unit);
183 }
184 else
185 {
186 /* Determine partition type */
187 PartTypeString[0] = '\0';
188 if (PartEntry->New != FALSE)
189 {
190 PartType = MUIGetString(STRING_UNFORMATTED);
191 }
192 else if (PartEntry->IsPartitioned != FALSE)
193 {
194 GetPartTypeStringFromPartitionType(PartEntry->PartitionType,
195 PartTypeString,
196 ARRAYSIZE(PartTypeString));
197 PartType = PartTypeString;
198 }
199
200 if (strcmp(PartType, MUIGetString(STRING_FORMATUNKNOWN)) == 0)
201 {
202 sprintf(LineBuffer,
203 MUIGetString(STRING_HDDINFOUNK5),
204 (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter,
205 (PartEntry->DriveLetter == 0) ? '-' : ':',
206 PartEntry->BootIndicator ? '*' : ' ',
207 PartEntry->LogicalPartition ? " " : "",
208 PartEntry->PartitionType,
209 PartEntry->LogicalPartition ? "" : " ",
210 PartSize.u.LowPart,
211 Unit);
212 }
213 else
214 {
215 sprintf(LineBuffer,
216 "%c%c %c %s%-24s%s %6lu %s",
217 (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter,
218 (PartEntry->DriveLetter == 0) ? '-' : ':',
219 PartEntry->BootIndicator ? '*' : ' ',
220 PartEntry->LogicalPartition ? " " : "",
221 PartType,
222 PartEntry->LogicalPartition ? "" : " ",
223 PartSize.u.LowPart,
224 Unit);
225 }
226 }
227
228 Attribute = (List->CurrentDisk == DiskEntry &&
229 List->CurrentPartition == PartEntry) ?
230 FOREGROUND_BLUE | BACKGROUND_WHITE :
231 FOREGROUND_WHITE | BACKGROUND_BLUE;
232
233 if (ListUi->Line >= 0 && ListUi->Line <= Height)
234 {
235 FillConsoleOutputCharacterA(StdOutput,
236 ' ',
237 Width,
238 coPos,
239 &Written);
240 }
241 coPos.X += 4;
242 Width -= 8;
243 if (ListUi->Line >= 0 && ListUi->Line <= Height)
244 {
245 FillConsoleOutputAttribute(StdOutput,
246 Attribute,
247 Width,
248 coPos,
249 &Written);
250 }
251 coPos.X++;
252 Width -= 2;
253 if (ListUi->Line >= 0 && ListUi->Line <= Height)
254 {
255 WriteConsoleOutputCharacterA(StdOutput,
256 LineBuffer,
257 min(strlen(LineBuffer), Width),
258 coPos,
259 &Written);
260 }
261
262 ListUi->Line++;
263 }
264
265 static
266 VOID
267 PrintDiskData(
268 IN PPARTLIST_UI ListUi,
269 IN PDISKENTRY DiskEntry)
270 {
271 // PPARTLIST List = ListUi->List;
272 PPARTENTRY PrimaryPartEntry, LogicalPartEntry;
273 PLIST_ENTRY PrimaryEntry, LogicalEntry;
274 CHAR LineBuffer[128];
275 COORD coPos;
276 ULONG Written;
277 USHORT Width;
278 USHORT Height;
279 ULARGE_INTEGER DiskSize;
280 PCHAR Unit;
281
282 Width = ListUi->Right - ListUi->Left - 1;
283 Height = ListUi->Bottom - ListUi->Top - 2;
284
285 coPos.X = ListUi->Left + 1;
286 coPos.Y = ListUi->Top + 1 + ListUi->Line;
287
288 DiskSize.QuadPart = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
289 if (DiskSize.QuadPart >= 10 * GB) /* 10 GB */
290 {
291 DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, GB);
292 Unit = MUIGetString(STRING_GB);
293 }
294 else
295 {
296 DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, MB);
297 if (DiskSize.QuadPart == 0)
298 DiskSize.QuadPart = 1;
299 Unit = MUIGetString(STRING_MB);
300 }
301
302 //
303 // FIXME: We *MUST* use TXTSETUP.SIF strings from section "DiskDriverMap" !!
304 //
305 if (DiskEntry->DriverName.Length > 0)
306 {
307 sprintf(LineBuffer,
308 MUIGetString(STRING_HDINFOPARTSELECT_1),
309 DiskSize.u.LowPart,
310 Unit,
311 DiskEntry->DiskNumber,
312 DiskEntry->Port,
313 DiskEntry->Bus,
314 DiskEntry->Id,
315 &DiskEntry->DriverName,
316 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
317 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
318 "RAW");
319 }
320 else
321 {
322 sprintf(LineBuffer,
323 MUIGetString(STRING_HDINFOPARTSELECT_2),
324 DiskSize.u.LowPart,
325 Unit,
326 DiskEntry->DiskNumber,
327 DiskEntry->Port,
328 DiskEntry->Bus,
329 DiskEntry->Id,
330 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
331 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
332 "RAW");
333 }
334
335 if (ListUi->Line >= 0 && ListUi->Line <= Height)
336 {
337 FillConsoleOutputAttribute(StdOutput,
338 FOREGROUND_WHITE | BACKGROUND_BLUE,
339 Width,
340 coPos,
341 &Written);
342
343 FillConsoleOutputCharacterA(StdOutput,
344 ' ',
345 Width,
346 coPos,
347 &Written);
348 }
349
350 coPos.X++;
351 if (ListUi->Line >= 0 && ListUi->Line <= Height)
352 {
353 WriteConsoleOutputCharacterA(StdOutput,
354 LineBuffer,
355 min((USHORT)strlen(LineBuffer), Width - 2),
356 coPos,
357 &Written);
358 }
359
360 ListUi->Line++;
361
362 /* Print separator line */
363 PrintEmptyLine(ListUi);
364
365 /* Print partition lines */
366 PrimaryEntry = DiskEntry->PrimaryPartListHead.Flink;
367 while (PrimaryEntry != &DiskEntry->PrimaryPartListHead)
368 {
369 PrimaryPartEntry = CONTAINING_RECORD(PrimaryEntry, PARTENTRY, ListEntry);
370
371 PrintPartitionData(ListUi,
372 DiskEntry,
373 PrimaryPartEntry);
374
375 if (IsContainerPartition(PrimaryPartEntry->PartitionType))
376 {
377 LogicalEntry = DiskEntry->LogicalPartListHead.Flink;
378 while (LogicalEntry != &DiskEntry->LogicalPartListHead)
379 {
380 LogicalPartEntry = CONTAINING_RECORD(LogicalEntry, PARTENTRY, ListEntry);
381
382 PrintPartitionData(ListUi,
383 DiskEntry,
384 LogicalPartEntry);
385
386 LogicalEntry = LogicalEntry->Flink;
387 }
388 }
389
390 PrimaryEntry = PrimaryEntry->Flink;
391 }
392
393 /* Print separator line */
394 PrintEmptyLine(ListUi);
395 }
396
397 VOID
398 DrawPartitionList(
399 IN PPARTLIST_UI ListUi)
400 {
401 PPARTLIST List = ListUi->List;
402 PLIST_ENTRY Entry, Entry2;
403 PDISKENTRY DiskEntry;
404 PPARTENTRY PartEntry = NULL;
405 COORD coPos;
406 ULONG Written;
407 SHORT i;
408 SHORT CurrentDiskLine;
409 SHORT CurrentPartLine;
410 SHORT LastLine;
411 BOOLEAN CurrentPartLineFound = FALSE;
412 BOOLEAN CurrentDiskLineFound = FALSE;
413
414 /* Calculate the line of the current disk and partition */
415 CurrentDiskLine = 0;
416 CurrentPartLine = 0;
417 LastLine = 0;
418
419 Entry = List->DiskListHead.Flink;
420 while (Entry != &List->DiskListHead)
421 {
422 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
423
424 LastLine += 2;
425 if (CurrentPartLineFound == FALSE)
426 {
427 CurrentPartLine += 2;
428 }
429
430 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
431 while (Entry2 != &DiskEntry->PrimaryPartListHead)
432 {
433 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
434 if (PartEntry == List->CurrentPartition)
435 {
436 CurrentPartLineFound = TRUE;
437 }
438
439 Entry2 = Entry2->Flink;
440 if (CurrentPartLineFound == FALSE)
441 {
442 CurrentPartLine++;
443 }
444
445 LastLine++;
446 }
447
448 if (CurrentPartLineFound == FALSE)
449 {
450 Entry2 = DiskEntry->LogicalPartListHead.Flink;
451 while (Entry2 != &DiskEntry->LogicalPartListHead)
452 {
453 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
454 if (PartEntry == List->CurrentPartition)
455 {
456 CurrentPartLineFound = TRUE;
457 }
458
459 Entry2 = Entry2->Flink;
460 if (CurrentPartLineFound == FALSE)
461 {
462 CurrentPartLine++;
463 }
464
465 LastLine++;
466 }
467 }
468
469 if (DiskEntry == List->CurrentDisk)
470 {
471 CurrentDiskLineFound = TRUE;
472 }
473
474 Entry = Entry->Flink;
475 if (Entry != &List->DiskListHead)
476 {
477 if (CurrentDiskLineFound == FALSE)
478 {
479 CurrentPartLine ++;
480 CurrentDiskLine = CurrentPartLine;
481 }
482
483 LastLine++;
484 }
485 else
486 {
487 LastLine--;
488 }
489 }
490
491 /* If it possible, make the disk name visible */
492 if (CurrentPartLine < ListUi->Offset)
493 {
494 ListUi->Offset = CurrentPartLine;
495 }
496 else if (CurrentPartLine - ListUi->Offset > ListUi->Bottom - ListUi->Top - 2)
497 {
498 ListUi->Offset = CurrentPartLine - (ListUi->Bottom - ListUi->Top - 2);
499 }
500
501 if (CurrentDiskLine < ListUi->Offset && CurrentPartLine - CurrentDiskLine < ListUi->Bottom - ListUi->Top - 2)
502 {
503 ListUi->Offset = CurrentDiskLine;
504 }
505
506 /* Draw upper left corner */
507 coPos.X = ListUi->Left;
508 coPos.Y = ListUi->Top;
509 FillConsoleOutputCharacterA(StdOutput,
510 0xDA, // '+',
511 1,
512 coPos,
513 &Written);
514
515 /* Draw upper edge */
516 coPos.X = ListUi->Left + 1;
517 coPos.Y = ListUi->Top;
518 if (ListUi->Offset == 0)
519 {
520 FillConsoleOutputCharacterA(StdOutput,
521 0xC4, // '-',
522 ListUi->Right - ListUi->Left - 1,
523 coPos,
524 &Written);
525 }
526 else
527 {
528 FillConsoleOutputCharacterA(StdOutput,
529 0xC4, // '-',
530 ListUi->Right - ListUi->Left - 5,
531 coPos,
532 &Written);
533 coPos.X = ListUi->Right - 5;
534 WriteConsoleOutputCharacterA(StdOutput,
535 "(\x18)", // "(up)"
536 3,
537 coPos,
538 &Written);
539 coPos.X = ListUi->Right - 2;
540 FillConsoleOutputCharacterA(StdOutput,
541 0xC4, // '-',
542 2,
543 coPos,
544 &Written);
545 }
546
547 /* Draw upper right corner */
548 coPos.X = ListUi->Right;
549 coPos.Y = ListUi->Top;
550 FillConsoleOutputCharacterA(StdOutput,
551 0xBF, // '+',
552 1,
553 coPos,
554 &Written);
555
556 /* Draw left and right edge */
557 for (i = ListUi->Top + 1; i < ListUi->Bottom; i++)
558 {
559 coPos.X = ListUi->Left;
560 coPos.Y = i;
561 FillConsoleOutputCharacterA(StdOutput,
562 0xB3, // '|',
563 1,
564 coPos,
565 &Written);
566
567 coPos.X = ListUi->Right;
568 FillConsoleOutputCharacterA(StdOutput,
569 0xB3, //'|',
570 1,
571 coPos,
572 &Written);
573 }
574
575 /* Draw lower left corner */
576 coPos.X = ListUi->Left;
577 coPos.Y = ListUi->Bottom;
578 FillConsoleOutputCharacterA(StdOutput,
579 0xC0, // '+',
580 1,
581 coPos,
582 &Written);
583
584 /* Draw lower edge */
585 coPos.X = ListUi->Left + 1;
586 coPos.Y = ListUi->Bottom;
587 if (LastLine - ListUi->Offset <= ListUi->Bottom - ListUi->Top - 2)
588 {
589 FillConsoleOutputCharacterA(StdOutput,
590 0xC4, // '-',
591 ListUi->Right - ListUi->Left - 1,
592 coPos,
593 &Written);
594 }
595 else
596 {
597 FillConsoleOutputCharacterA(StdOutput,
598 0xC4, // '-',
599 ListUi->Right - ListUi->Left - 5,
600 coPos,
601 &Written);
602 coPos.X = ListUi->Right - 5;
603 WriteConsoleOutputCharacterA(StdOutput,
604 "(\x19)", // "(down)"
605 3,
606 coPos,
607 &Written);
608 coPos.X = ListUi->Right - 2;
609 FillConsoleOutputCharacterA(StdOutput,
610 0xC4, // '-',
611 2,
612 coPos,
613 &Written);
614 }
615
616 /* Draw lower right corner */
617 coPos.X = ListUi->Right;
618 coPos.Y = ListUi->Bottom;
619 FillConsoleOutputCharacterA(StdOutput,
620 0xD9, // '+',
621 1,
622 coPos,
623 &Written);
624
625 /* print list entries */
626 ListUi->Line = - ListUi->Offset;
627
628 Entry = List->DiskListHead.Flink;
629 while (Entry != &List->DiskListHead)
630 {
631 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
632
633 /* Print disk entry */
634 PrintDiskData(ListUi, DiskEntry);
635
636 Entry = Entry->Flink;
637 }
638 }
639
640 VOID
641 ScrollDownPartitionList(
642 IN PPARTLIST_UI ListUi)
643 {
644 if (GetNextPartition(ListUi->List))
645 DrawPartitionList(ListUi);
646 }
647
648 VOID
649 ScrollUpPartitionList(
650 IN PPARTLIST_UI ListUi)
651 {
652 if (GetPrevPartition(ListUi->List))
653 DrawPartitionList(ListUi);
654 }
655
656 /* EOF */