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