[SETUPLIB][USETUP] Introduce a 'SetupLib' library. CORE-13544
[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: Eric Kohl
24 * 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 typedef struct _PARTITION_TYPE
35 {
36 UCHAR Type;
37 PCHAR Description;
38 } PARTITION_TYPE, *PPARTITION_TYPE;
39
40 /*
41 * This partition type list was ripped off the kernelDisk.c module from:
42 *
43 * Visopsys Operating System
44 * Copyright (C) 1998-2015 J. Andrew McLaughlin
45 *
46 * This program is free software; you can redistribute it and/or modify it
47 * under the terms of the GNU General Public License as published by the Free
48 * Software Foundation; either version 2 of the License, or (at your option)
49 * any later version.
50 *
51 * This program is distributed in the hope that it will be useful, but
52 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
53 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
54 * for more details.
55 *
56 * You should have received a copy of the GNU General Public License along
57 * with this program; if not, write to the Free Software Foundation, Inc.,
58 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
59 *
60 *
61 * See also https://en.wikipedia.org/wiki/Partition_type#List_of_partition_IDs
62 * and http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
63 * for a complete list.
64 */
65
66 /* This is a table for keeping known partition type codes and descriptions */
67 static PARTITION_TYPE PartitionTypes[] =
68 {
69 { 0x00, "(Empty)" },
70 { 0x01, "FAT12" },
71 { 0x02, "XENIX root" },
72 { 0x03, "XENIX /usr" },
73 { 0x04, "FAT16 (small)" },
74 { 0x05, "Extended" },
75 { 0x06, "FAT16" },
76 { 0x07, "NTFS/HPFS/exFAT" },
77 { 0x08, "OS/2 or AIX boot" },
78 { 0x09, "AIX data" },
79 { 0x0A, "OS/2 Boot Manager" },
80 { 0x0B, "FAT32" },
81 { 0x0C, "FAT32 (LBA)" },
82 { 0x0E, "FAT16 (LBA)" },
83 { 0x0F, "Extended (LBA)" },
84 { 0x11, "Hidden FAT12" },
85 { 0x12, "FAT diagnostic" },
86 { 0x14, "Hidden FAT16 (small)" },
87 { 0x16, "Hidden FAT16" },
88 { 0x17, "Hidden HPFS or NTFS" },
89 { 0x1B, "Hidden FAT32" },
90 { 0x1C, "Hidden FAT32 (LBA)" },
91 { 0x1E, "Hidden FAT16 (LBA)" },
92 { 0x35, "JFS" },
93 { 0x39, "Plan 9" },
94 { 0x3C, "PartitionMagic" },
95 { 0x3D, "Hidden Netware" },
96 { 0x41, "PowerPC PReP" },
97 { 0x42, "Win2K dynamic extended" },
98 { 0x43, "Old Linux" },
99 { 0x44, "GoBack" },
100 { 0x4D, "QNX4.x" },
101 { 0x4D, "QNX4.x 2nd" },
102 { 0x4D, "QNX4.x 3rd" },
103 { 0x50, "Ontrack R/O" },
104 { 0x51, "Ontrack R/W or Novell" },
105 { 0x52, "CP/M" },
106 { 0x63, "GNU HURD or UNIX SysV" },
107 { 0x64, "Netware 2" },
108 { 0x65, "Netware 3/4" },
109 { 0x66, "Netware SMS" },
110 { 0x67, "Novell" },
111 { 0x68, "Novell" },
112 { 0x69, "Netware 5+" },
113 { 0x7E, "Veritas VxVM public" },
114 { 0x7F, "Veritas VxVM private" },
115 { 0x80, "Minix" },
116 { 0x81, "Linux or Minix" },
117 { 0x82, "Linux swap or Solaris" },
118 { 0x83, "Linux" },
119 { 0x84, "Hibernation" },
120 { 0x85, "Linux extended" },
121 { 0x86, "HPFS or NTFS mirrored" },
122 { 0x87, "HPFS or NTFS mirrored" },
123 { 0x8E, "Linux LVM" },
124 { 0x93, "Hidden Linux" },
125 { 0x96, "CDFS/ISO-9660" },
126 { 0x9F, "BSD/OS" },
127 { 0xA0, "Laptop hibernation" },
128 { 0xA1, "Laptop hibernation" },
129 { 0xA5, "BSD, NetBSD, FreeBSD" },
130 { 0xA6, "OpenBSD" },
131 { 0xA7, "NeXTSTEP" },
132 { 0xA8, "OS-X UFS" },
133 { 0xA9, "NetBSD" },
134 { 0xAB, "OS-X boot" },
135 { 0xAF, "OS-X HFS" },
136 { 0xB6, "NT corrupt mirror" },
137 { 0xB7, "BSDI" },
138 { 0xB8, "BSDI swap" },
139 { 0xBE, "Solaris 8 boot" },
140 { 0xBF, "Solaris x86" },
141 { 0xC0, "NTFT" },
142 { 0xC1, "DR-DOS FAT12" },
143 { 0xC2, "Hidden Linux" },
144 { 0xC3, "Hidden Linux swap" },
145 { 0xC4, "DR-DOS FAT16 (small)" },
146 { 0xC5, "DR-DOS Extended" },
147 { 0xC6, "DR-DOS FAT16" },
148 { 0xC7, "HPFS mirrored" },
149 { 0xCB, "DR-DOS FAT32" },
150 { 0xCC, "DR-DOS FAT32 (LBA)" },
151 { 0xCE, "DR-DOS FAT16 (LBA)" },
152 { 0xD0, "MDOS" },
153 { 0xD1, "MDOS FAT12" },
154 { 0xD4, "MDOS FAT16 (small)" },
155 { 0xD5, "MDOS Extended" },
156 { 0xD6, "MDOS FAT16" },
157 { 0xD8, "CP/M-86" },
158 { 0xDF, "BootIt EMBRM(FAT16/32)" },
159 { 0xEB, "BeOS BFS" },
160 { 0xEE, "EFI GPT protective" },
161 { 0xEF, "EFI filesystem" },
162 { 0xF0, "Linux/PA-RISC boot" },
163 { 0xF2, "DOS 3.3+ second" },
164 { 0xFA, "Bochs" },
165 { 0xFB, "VmWare" },
166 { 0xFC, "VmWare swap" },
167 { 0xFD, "Linux RAID" },
168 { 0xFE, "NT hidden" },
169 };
170
171 VOID
172 GetPartTypeStringFromPartitionType(
173 IN UCHAR partitionType,
174 OUT PCHAR strPartType,
175 IN ULONG cchPartType)
176 {
177 /* Determine partition type */
178
179 if (IsContainerPartition(partitionType))
180 {
181 RtlStringCchCopyA(strPartType, cchPartType, MUIGetString(STRING_EXTENDED_PARTITION));
182 }
183 else if (partitionType == PARTITION_ENTRY_UNUSED)
184 {
185 RtlStringCchCopyA(strPartType, cchPartType, MUIGetString(STRING_FORMATUNUSED));
186 }
187 else
188 {
189 UINT i;
190
191 /* Do the table lookup */
192 for (i = 0; i < ARRAYSIZE(PartitionTypes); i++)
193 {
194 if (partitionType == PartitionTypes[i].Type)
195 {
196 RtlStringCchCopyA(strPartType, cchPartType, PartitionTypes[i].Description);
197 return;
198 }
199 }
200
201 /* We are here because the partition type is unknown */
202 RtlStringCchCopyA(strPartType, cchPartType, MUIGetString(STRING_FORMATUNKNOWN));
203 }
204 }
205
206
207 /* FUNCTIONS ****************************************************************/
208
209 VOID
210 InitPartitionListUi(
211 IN OUT PPARTLIST_UI ListUi,
212 IN PPARTLIST List,
213 IN SHORT Left,
214 IN SHORT Top,
215 IN SHORT Right,
216 IN SHORT Bottom)
217 {
218 ListUi->List = List;
219 // ListUi->FirstShown = NULL;
220 // ListUi->LastShown = NULL;
221
222 ListUi->Left = Left;
223 ListUi->Top = Top;
224 ListUi->Right = Right;
225 ListUi->Bottom = Bottom;
226
227 ListUi->Line = 0;
228 ListUi->Offset = 0;
229
230 // ListUi->Redraw = TRUE;
231 }
232
233 static
234 VOID
235 PrintEmptyLine(
236 IN PPARTLIST_UI ListUi)
237 {
238 COORD coPos;
239 ULONG Written;
240 USHORT Width;
241 USHORT Height;
242
243 Width = ListUi->Right - ListUi->Left - 1;
244 Height = ListUi->Bottom - ListUi->Top - 2;
245
246 coPos.X = ListUi->Left + 1;
247 coPos.Y = ListUi->Top + 1 + ListUi->Line;
248
249 if (ListUi->Line >= 0 && ListUi->Line <= Height)
250 {
251 FillConsoleOutputAttribute(StdOutput,
252 FOREGROUND_WHITE | BACKGROUND_BLUE,
253 Width,
254 coPos,
255 &Written);
256
257 FillConsoleOutputCharacterA(StdOutput,
258 ' ',
259 Width,
260 coPos,
261 &Written);
262 }
263
264 ListUi->Line++;
265 }
266
267 static
268 VOID
269 PrintPartitionData(
270 IN PPARTLIST_UI ListUi,
271 IN PDISKENTRY DiskEntry,
272 IN PPARTENTRY PartEntry)
273 {
274 PPARTLIST List = ListUi->List;
275 CHAR LineBuffer[128];
276 COORD coPos;
277 ULONG Written;
278 USHORT Width;
279 USHORT Height;
280 LARGE_INTEGER PartSize;
281 PCHAR Unit;
282 UCHAR Attribute;
283 CHAR PartTypeString[32];
284 PCHAR PartType = PartTypeString;
285
286 Width = ListUi->Right - ListUi->Left - 1;
287 Height = ListUi->Bottom - ListUi->Top - 2;
288
289 coPos.X = ListUi->Left + 1;
290 coPos.Y = ListUi->Top + 1 + ListUi->Line;
291
292 if (PartEntry->IsPartitioned == FALSE)
293 {
294 PartSize.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
295 #if 0
296 if (PartSize.QuadPart >= 10737418240) /* 10 GB */
297 {
298 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1073741824);
299 Unit = MUIGetString(STRING_GB);
300 }
301 else
302 #endif
303 if (PartSize.QuadPart >= 10485760) /* 10 MB */
304 {
305 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1048576);
306 Unit = MUIGetString(STRING_MB);
307 }
308 else
309 {
310 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1024);
311 Unit = MUIGetString(STRING_KB);
312 }
313
314 sprintf(LineBuffer,
315 MUIGetString(STRING_UNPSPACE),
316 PartEntry->LogicalPartition ? " " : "",
317 PartEntry->LogicalPartition ? "" : " ",
318 PartSize.u.LowPart,
319 Unit);
320 }
321 else
322 {
323 /* Determine partition type */
324 PartTypeString[0] = '\0';
325 if (PartEntry->New != FALSE)
326 {
327 PartType = MUIGetString(STRING_UNFORMATTED);
328 }
329 else if (PartEntry->IsPartitioned != FALSE)
330 {
331 GetPartTypeStringFromPartitionType(PartEntry->PartitionType,
332 PartTypeString,
333 ARRAYSIZE(PartTypeString));
334 PartType = PartTypeString;
335 }
336
337 PartSize.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
338 #if 0
339 if (PartSize.QuadPart >= 10737418240) /* 10 GB */
340 {
341 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1073741824);
342 Unit = MUIGetString(STRING_GB);
343 }
344 else
345 #endif
346 if (PartSize.QuadPart >= 10485760) /* 10 MB */
347 {
348 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1048576);
349 Unit = MUIGetString(STRING_MB);
350 }
351 else
352 {
353 PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1024);
354 Unit = MUIGetString(STRING_KB);
355 }
356
357 if (strcmp(PartType, MUIGetString(STRING_FORMATUNKNOWN)) == 0)
358 {
359 sprintf(LineBuffer,
360 MUIGetString(STRING_HDDINFOUNK5),
361 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
362 (PartEntry->DriveLetter == 0) ? '-' : ':',
363 PartEntry->BootIndicator ? '*' : ' ',
364 PartEntry->LogicalPartition ? " " : "",
365 PartEntry->PartitionType,
366 PartEntry->LogicalPartition ? "" : " ",
367 PartSize.u.LowPart,
368 Unit);
369 }
370 else
371 {
372 sprintf(LineBuffer,
373 "%c%c %c %s%-24s%s %6lu %s",
374 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
375 (PartEntry->DriveLetter == 0) ? '-' : ':',
376 PartEntry->BootIndicator ? '*' : ' ',
377 PartEntry->LogicalPartition ? " " : "",
378 PartType,
379 PartEntry->LogicalPartition ? "" : " ",
380 PartSize.u.LowPart,
381 Unit);
382 }
383 }
384
385 Attribute = (List->CurrentDisk == DiskEntry &&
386 List->CurrentPartition == PartEntry) ?
387 FOREGROUND_BLUE | BACKGROUND_WHITE :
388 FOREGROUND_WHITE | BACKGROUND_BLUE;
389
390 if (ListUi->Line >= 0 && ListUi->Line <= Height)
391 {
392 FillConsoleOutputCharacterA(StdOutput,
393 ' ',
394 Width,
395 coPos,
396 &Written);
397 }
398 coPos.X += 4;
399 Width -= 8;
400 if (ListUi->Line >= 0 && ListUi->Line <= Height)
401 {
402 FillConsoleOutputAttribute(StdOutput,
403 Attribute,
404 Width,
405 coPos,
406 &Written);
407 }
408 coPos.X++;
409 Width -= 2;
410 if (ListUi->Line >= 0 && ListUi->Line <= Height)
411 {
412 WriteConsoleOutputCharacterA(StdOutput,
413 LineBuffer,
414 min(strlen(LineBuffer), Width),
415 coPos,
416 &Written);
417 }
418
419 ListUi->Line++;
420 }
421
422 static
423 VOID
424 PrintDiskData(
425 IN PPARTLIST_UI ListUi,
426 IN PDISKENTRY DiskEntry)
427 {
428 // PPARTLIST List = ListUi->List;
429 PPARTENTRY PrimaryPartEntry, LogicalPartEntry;
430 PLIST_ENTRY PrimaryEntry, LogicalEntry;
431 CHAR LineBuffer[128];
432 COORD coPos;
433 ULONG Written;
434 USHORT Width;
435 USHORT Height;
436 ULARGE_INTEGER DiskSize;
437 PCHAR Unit;
438
439 Width = ListUi->Right - ListUi->Left - 1;
440 Height = ListUi->Bottom - ListUi->Top - 2;
441
442 coPos.X = ListUi->Left + 1;
443 coPos.Y = ListUi->Top + 1 + ListUi->Line;
444
445 DiskSize.QuadPart = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
446 if (DiskSize.QuadPart >= 10737418240) /* 10 GB */
447 {
448 DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, 1073741824);
449 Unit = MUIGetString(STRING_GB);
450 }
451 else
452 {
453 DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, 1048576);
454 if (DiskSize.QuadPart == 0)
455 DiskSize.QuadPart = 1;
456 Unit = MUIGetString(STRING_MB);
457 }
458
459 if (DiskEntry->DriverName.Length > 0)
460 {
461 sprintf(LineBuffer,
462 MUIGetString(STRING_HDINFOPARTSELECT),
463 DiskSize.u.LowPart,
464 Unit,
465 DiskEntry->DiskNumber,
466 DiskEntry->Port,
467 DiskEntry->Bus,
468 DiskEntry->Id,
469 DiskEntry->DriverName.Buffer);
470 }
471 else
472 {
473 sprintf(LineBuffer,
474 MUIGetString(STRING_HDDINFOUNK6),
475 DiskSize.u.LowPart,
476 Unit,
477 DiskEntry->DiskNumber,
478 DiskEntry->Port,
479 DiskEntry->Bus,
480 DiskEntry->Id);
481 }
482
483 if (ListUi->Line >= 0 && ListUi->Line <= Height)
484 {
485 FillConsoleOutputAttribute(StdOutput,
486 FOREGROUND_WHITE | BACKGROUND_BLUE,
487 Width,
488 coPos,
489 &Written);
490
491 FillConsoleOutputCharacterA(StdOutput,
492 ' ',
493 Width,
494 coPos,
495 &Written);
496 }
497
498 coPos.X++;
499 if (ListUi->Line >= 0 && ListUi->Line <= Height)
500 {
501 WriteConsoleOutputCharacterA(StdOutput,
502 LineBuffer,
503 min((USHORT)strlen(LineBuffer), Width - 2),
504 coPos,
505 &Written);
506 }
507
508 ListUi->Line++;
509
510 /* Print separator line */
511 PrintEmptyLine(ListUi);
512
513 /* Print partition lines */
514 PrimaryEntry = DiskEntry->PrimaryPartListHead.Flink;
515 while (PrimaryEntry != &DiskEntry->PrimaryPartListHead)
516 {
517 PrimaryPartEntry = CONTAINING_RECORD(PrimaryEntry, PARTENTRY, ListEntry);
518
519 PrintPartitionData(ListUi,
520 DiskEntry,
521 PrimaryPartEntry);
522
523 if (IsContainerPartition(PrimaryPartEntry->PartitionType))
524 {
525 LogicalEntry = DiskEntry->LogicalPartListHead.Flink;
526 while (LogicalEntry != &DiskEntry->LogicalPartListHead)
527 {
528 LogicalPartEntry = CONTAINING_RECORD(LogicalEntry, PARTENTRY, ListEntry);
529
530 PrintPartitionData(ListUi,
531 DiskEntry,
532 LogicalPartEntry);
533
534 LogicalEntry = LogicalEntry->Flink;
535 }
536 }
537
538 PrimaryEntry = PrimaryEntry->Flink;
539 }
540
541 /* Print separator line */
542 PrintEmptyLine(ListUi);
543 }
544
545 VOID
546 DrawPartitionList(
547 IN PPARTLIST_UI ListUi)
548 {
549 PPARTLIST List = ListUi->List;
550 PLIST_ENTRY Entry, Entry2;
551 PDISKENTRY DiskEntry;
552 PPARTENTRY PartEntry = NULL;
553 COORD coPos;
554 ULONG Written;
555 SHORT i;
556 SHORT CurrentDiskLine;
557 SHORT CurrentPartLine;
558 SHORT LastLine;
559 BOOLEAN CurrentPartLineFound = FALSE;
560 BOOLEAN CurrentDiskLineFound = FALSE;
561
562 /* Calculate the line of the current disk and partition */
563 CurrentDiskLine = 0;
564 CurrentPartLine = 0;
565 LastLine = 0;
566
567 Entry = List->DiskListHead.Flink;
568 while (Entry != &List->DiskListHead)
569 {
570 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
571
572 LastLine += 2;
573 if (CurrentPartLineFound == FALSE)
574 {
575 CurrentPartLine += 2;
576 }
577
578 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
579 while (Entry2 != &DiskEntry->PrimaryPartListHead)
580 {
581 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
582 if (PartEntry == List->CurrentPartition)
583 {
584 CurrentPartLineFound = TRUE;
585 }
586
587 Entry2 = Entry2->Flink;
588 if (CurrentPartLineFound == FALSE)
589 {
590 CurrentPartLine++;
591 }
592
593 LastLine++;
594 }
595
596 if (CurrentPartLineFound == FALSE)
597 {
598 Entry2 = DiskEntry->LogicalPartListHead.Flink;
599 while (Entry2 != &DiskEntry->LogicalPartListHead)
600 {
601 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
602 if (PartEntry == List->CurrentPartition)
603 {
604 CurrentPartLineFound = TRUE;
605 }
606
607 Entry2 = Entry2->Flink;
608 if (CurrentPartLineFound == FALSE)
609 {
610 CurrentPartLine++;
611 }
612
613 LastLine++;
614 }
615 }
616
617 if (DiskEntry == List->CurrentDisk)
618 {
619 CurrentDiskLineFound = TRUE;
620 }
621
622 Entry = Entry->Flink;
623 if (Entry != &List->DiskListHead)
624 {
625 if (CurrentDiskLineFound == FALSE)
626 {
627 CurrentPartLine ++;
628 CurrentDiskLine = CurrentPartLine;
629 }
630
631 LastLine++;
632 }
633 else
634 {
635 LastLine--;
636 }
637 }
638
639 /* If it possible, make the disk name visible */
640 if (CurrentPartLine < ListUi->Offset)
641 {
642 ListUi->Offset = CurrentPartLine;
643 }
644 else if (CurrentPartLine - ListUi->Offset > ListUi->Bottom - ListUi->Top - 2)
645 {
646 ListUi->Offset = CurrentPartLine - (ListUi->Bottom - ListUi->Top - 2);
647 }
648
649 if (CurrentDiskLine < ListUi->Offset && CurrentPartLine - CurrentDiskLine < ListUi->Bottom - ListUi->Top - 2)
650 {
651 ListUi->Offset = CurrentDiskLine;
652 }
653
654 /* Draw upper left corner */
655 coPos.X = ListUi->Left;
656 coPos.Y = ListUi->Top;
657 FillConsoleOutputCharacterA(StdOutput,
658 0xDA, // '+',
659 1,
660 coPos,
661 &Written);
662
663 /* Draw upper edge */
664 coPos.X = ListUi->Left + 1;
665 coPos.Y = ListUi->Top;
666 if (ListUi->Offset == 0)
667 {
668 FillConsoleOutputCharacterA(StdOutput,
669 0xC4, // '-',
670 ListUi->Right - ListUi->Left - 1,
671 coPos,
672 &Written);
673 }
674 else
675 {
676 FillConsoleOutputCharacterA(StdOutput,
677 0xC4, // '-',
678 ListUi->Right - ListUi->Left - 5,
679 coPos,
680 &Written);
681 coPos.X = ListUi->Right - 5;
682 WriteConsoleOutputCharacterA(StdOutput,
683 "(\x18)", // "(up)"
684 3,
685 coPos,
686 &Written);
687 coPos.X = ListUi->Right - 2;
688 FillConsoleOutputCharacterA(StdOutput,
689 0xC4, // '-',
690 2,
691 coPos,
692 &Written);
693 }
694
695 /* Draw upper right corner */
696 coPos.X = ListUi->Right;
697 coPos.Y = ListUi->Top;
698 FillConsoleOutputCharacterA(StdOutput,
699 0xBF, // '+',
700 1,
701 coPos,
702 &Written);
703
704 /* Draw left and right edge */
705 for (i = ListUi->Top + 1; i < ListUi->Bottom; i++)
706 {
707 coPos.X = ListUi->Left;
708 coPos.Y = i;
709 FillConsoleOutputCharacterA(StdOutput,
710 0xB3, // '|',
711 1,
712 coPos,
713 &Written);
714
715 coPos.X = ListUi->Right;
716 FillConsoleOutputCharacterA(StdOutput,
717 0xB3, //'|',
718 1,
719 coPos,
720 &Written);
721 }
722
723 /* Draw lower left corner */
724 coPos.X = ListUi->Left;
725 coPos.Y = ListUi->Bottom;
726 FillConsoleOutputCharacterA(StdOutput,
727 0xC0, // '+',
728 1,
729 coPos,
730 &Written);
731
732 /* Draw lower edge */
733 coPos.X = ListUi->Left + 1;
734 coPos.Y = ListUi->Bottom;
735 if (LastLine - ListUi->Offset <= ListUi->Bottom - ListUi->Top - 2)
736 {
737 FillConsoleOutputCharacterA(StdOutput,
738 0xC4, // '-',
739 ListUi->Right - ListUi->Left - 1,
740 coPos,
741 &Written);
742 }
743 else
744 {
745 FillConsoleOutputCharacterA(StdOutput,
746 0xC4, // '-',
747 ListUi->Right - ListUi->Left - 5,
748 coPos,
749 &Written);
750 coPos.X = ListUi->Right - 5;
751 WriteConsoleOutputCharacterA(StdOutput,
752 "(\x19)", // "(down)"
753 3,
754 coPos,
755 &Written);
756 coPos.X = ListUi->Right - 2;
757 FillConsoleOutputCharacterA(StdOutput,
758 0xC4, // '-',
759 2,
760 coPos,
761 &Written);
762 }
763
764 /* Draw lower right corner */
765 coPos.X = ListUi->Right;
766 coPos.Y = ListUi->Bottom;
767 FillConsoleOutputCharacterA(StdOutput,
768 0xD9, // '+',
769 1,
770 coPos,
771 &Written);
772
773 /* print list entries */
774 ListUi->Line = - ListUi->Offset;
775
776 Entry = List->DiskListHead.Flink;
777 while (Entry != &List->DiskListHead)
778 {
779 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
780
781 /* Print disk entry */
782 PrintDiskData(ListUi, DiskEntry);
783
784 Entry = Entry->Flink;
785 }
786 }
787
788 VOID
789 ScrollDownPartitionList(
790 IN PPARTLIST_UI ListUi)
791 {
792 if (GetNextPartition(ListUi->List))
793 DrawPartitionList(ListUi);
794 }
795
796 VOID
797 ScrollUpPartitionList(
798 IN PPARTLIST_UI ListUi)
799 {
800 if (GetPrevPartition(ListUi->List))
801 DrawPartitionList(ListUi);
802 }
803
804 /* EOF */