dtutils.c revision 256281
1/******************************************************************************
2 *
3 * Module Name: dtutils.c - Utility routines for the data table compiler
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2013, Intel Corp.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions, and the following disclaimer,
16 *    without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 *    substantially similar to the "NO WARRANTY" disclaimer below
19 *    ("Disclaimer") and any redistribution must be conditioned upon
20 *    including a substantially similar Disclaimer requirement for further
21 *    binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 *    of any contributors may be used to endorse or promote products derived
24 *    from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44#define __DTUTILS_C__
45
46#include <contrib/dev/acpica/compiler/aslcompiler.h>
47#include <contrib/dev/acpica/compiler/dtcompiler.h>
48#include <contrib/dev/acpica/include/actables.h>
49
50#define _COMPONENT          DT_COMPILER
51        ACPI_MODULE_NAME    ("dtutils")
52
53/* Local prototypes */
54
55static void
56DtSum (
57    DT_SUBTABLE             *Subtable,
58    void                    *Context,
59    void                    *ReturnValue);
60
61
62/******************************************************************************
63 *
64 * FUNCTION:    DtError
65 *
66 * PARAMETERS:  Level               - Seriousness (Warning/error, etc.)
67 *              MessageId           - Index into global message buffer
68 *              Op                  - Parse node where error happened
69 *              ExtraMessage        - additional error message
70 *
71 * RETURN:      None
72 *
73 * DESCRIPTION: Common error interface for data table compiler
74 *
75 *****************************************************************************/
76
77void
78DtError (
79    UINT8                   Level,
80    UINT8                   MessageId,
81    DT_FIELD                *FieldObject,
82    char                    *ExtraMessage)
83{
84
85    /* Check if user wants to ignore this exception */
86
87    if (AslIsExceptionDisabled (Level, MessageId))
88    {
89        return;
90    }
91
92    if (FieldObject)
93    {
94        AslCommonError (Level, MessageId,
95            FieldObject->Line,
96            FieldObject->Line,
97            FieldObject->ByteOffset,
98            FieldObject->Column,
99            Gbl_Files[ASL_FILE_INPUT].Filename, ExtraMessage);
100    }
101    else
102    {
103        AslCommonError (Level, MessageId, 0,
104            0, 0, 0, 0, ExtraMessage);
105    }
106}
107
108
109/******************************************************************************
110 *
111 * FUNCTION:    DtNameError
112 *
113 * PARAMETERS:  Level               - Seriousness (Warning/error, etc.)
114 *              MessageId           - Index into global message buffer
115 *              Op                  - Parse node where error happened
116 *              ExtraMessage        - additional error message
117 *
118 * RETURN:      None
119 *
120 * DESCRIPTION: Error interface for named objects
121 *
122 *****************************************************************************/
123
124void
125DtNameError (
126    UINT8                   Level,
127    UINT8                   MessageId,
128    DT_FIELD                *FieldObject,
129    char                    *ExtraMessage)
130{
131
132    switch (Level)
133    {
134    case ASL_WARNING2:
135    case ASL_WARNING3:
136
137        if (Gbl_WarningLevel < Level)
138        {
139            return;
140        }
141        break;
142
143    default:
144
145        break;
146    }
147
148    if (FieldObject)
149    {
150        AslCommonError (Level, MessageId,
151            FieldObject->Line,
152            FieldObject->Line,
153            FieldObject->ByteOffset,
154            FieldObject->NameColumn,
155            Gbl_Files[ASL_FILE_INPUT].Filename, ExtraMessage);
156    }
157    else
158    {
159        AslCommonError (Level, MessageId, 0,
160            0, 0, 0, 0, ExtraMessage);
161    }
162}
163
164
165/*******************************************************************************
166 *
167 * FUNCTION:    DtFatal
168 *
169 * PARAMETERS:  None
170 *
171 * RETURN:      None
172 *
173 * DESCRIPTION: Dump the error log and abort the compiler. Used for serious
174 *              compile or I/O errors
175 *
176 ******************************************************************************/
177
178void
179DtFatal (
180    UINT8                   MessageId,
181    DT_FIELD                *FieldObject,
182    char                    *ExtraMessage)
183{
184
185    DtError (ASL_ERROR, MessageId, FieldObject, ExtraMessage);
186
187/*
188 * TBD: remove this entire function, DtFatal
189 *
190 * We cannot abort the compiler on error, because we may be compiling a
191 * list of files. We must move on to the next file.
192 */
193#ifdef __OBSOLETE
194    CmCleanupAndExit ();
195    exit (1);
196#endif
197}
198
199
200/******************************************************************************
201 *
202 * FUNCTION:    DtStrtoul64
203 *
204 * PARAMETERS:  String              - Null terminated string
205 *              ReturnInteger       - Where the converted integer is returned
206 *
207 * RETURN:      Status
208 *
209 * DESCRIPTION: Simple conversion of a string hex integer constant to unsigned
210 *              value. Assumes no leading "0x" for the constant.
211 *
212 * Portability note: The reason this function exists is because a 64-bit
213 * sscanf is not available in all environments.
214 *
215 *****************************************************************************/
216
217ACPI_STATUS
218DtStrtoul64 (
219    char                    *String,
220    UINT64                  *ReturnInteger)
221{
222    char                    *ThisChar = String;
223    UINT32                  ThisDigit;
224    UINT64                  ReturnValue = 0;
225    int                     DigitCount = 0;
226
227
228    /* Skip over any white space in the buffer */
229
230    while ((*ThisChar == ' ') || (*ThisChar == '\t'))
231    {
232        ThisChar++;
233    }
234
235    /* Skip leading zeros */
236
237    while ((*ThisChar) == '0')
238    {
239        ThisChar++;
240    }
241
242    /* Convert character-by-character */
243
244    while (*ThisChar)
245    {
246        if (ACPI_IS_DIGIT (*ThisChar))
247        {
248            /* Convert ASCII 0-9 to Decimal value */
249
250            ThisDigit = ((UINT8) *ThisChar) - '0';
251        }
252        else /* Letter */
253        {
254            ThisDigit = (UINT32) ACPI_TOUPPER (*ThisChar);
255            if (!ACPI_IS_XDIGIT ((char) ThisDigit))
256            {
257                /* Not A-F */
258
259                return (AE_BAD_CHARACTER);
260            }
261
262            /* Convert ASCII Hex char (A-F) to value */
263
264            ThisDigit = (ThisDigit - 'A') + 10;
265        }
266
267        /* Insert the 4-bit hex digit */
268
269        ReturnValue <<= 4;
270        ReturnValue += ThisDigit;
271
272        ThisChar++;
273        DigitCount++;
274        if (DigitCount > 16)
275        {
276            /* Value is too large (> 64 bits/8 bytes/16 hex digits) */
277
278            return (AE_LIMIT);
279        }
280    }
281
282    *ReturnInteger = ReturnValue;
283    return (AE_OK);
284}
285
286
287/******************************************************************************
288 *
289 * FUNCTION:    DtGetFileSize
290 *
291 * PARAMETERS:  Handle              - Open file handler
292 *
293 * RETURN:      Current file size
294 *
295 * DESCRIPTION: Get the current size of a file. Seek to the EOF and get the
296 *              offset. Seek back to the original location.
297 *
298 *****************************************************************************/
299
300UINT32
301DtGetFileSize (
302    FILE                    *Handle)
303{
304    int                     CurrentOffset;
305    int                     LastOffset;
306
307
308    CurrentOffset = ftell (Handle);
309    fseek (Handle, 0, SEEK_END);
310    LastOffset = ftell (Handle);
311    fseek (Handle, CurrentOffset, SEEK_SET);
312
313    return ((UINT32) LastOffset);
314}
315
316
317/******************************************************************************
318 *
319 * FUNCTION:    DtGetFieldValue
320 *
321 * PARAMETERS:  Field               - Current field list pointer
322 *
323 * RETURN:      Field value
324 *
325 * DESCRIPTION: Get field value
326 *
327 *****************************************************************************/
328
329char *
330DtGetFieldValue (
331    DT_FIELD                *Field)
332{
333    if (!Field)
334    {
335        return (NULL);
336    }
337
338    return (Field->Value);
339}
340
341
342/******************************************************************************
343 *
344 * FUNCTION:    DtGetFieldType
345 *
346 * PARAMETERS:  Info                - Data table info
347 *
348 * RETURN:      Field type
349 *
350 * DESCRIPTION: Get field type
351 *
352 *****************************************************************************/
353
354UINT8
355DtGetFieldType (
356    ACPI_DMTABLE_INFO       *Info)
357{
358    UINT8                   Type;
359
360
361    /* DT_FLAG means that this is the start of a block of flag bits */
362    /* TBD - we can make these a separate opcode later */
363
364    if (Info->Flags & DT_FLAG)
365    {
366        return (DT_FIELD_TYPE_FLAGS_INTEGER);
367    }
368
369    /* Type is based upon the opcode for this field in the info table */
370
371    switch (Info->Opcode)
372    {
373    case ACPI_DMT_FLAG0:
374    case ACPI_DMT_FLAG1:
375    case ACPI_DMT_FLAG2:
376    case ACPI_DMT_FLAG3:
377    case ACPI_DMT_FLAG4:
378    case ACPI_DMT_FLAG5:
379    case ACPI_DMT_FLAG6:
380    case ACPI_DMT_FLAG7:
381    case ACPI_DMT_FLAGS0:
382    case ACPI_DMT_FLAGS1:
383    case ACPI_DMT_FLAGS2:
384    case ACPI_DMT_FLAGS4:
385
386        Type = DT_FIELD_TYPE_FLAG;
387        break;
388
389    case ACPI_DMT_NAME4:
390    case ACPI_DMT_SIG:
391    case ACPI_DMT_NAME6:
392    case ACPI_DMT_NAME8:
393    case ACPI_DMT_STRING:
394
395        Type = DT_FIELD_TYPE_STRING;
396        break;
397
398    case ACPI_DMT_BUFFER:
399    case ACPI_DMT_BUF7:
400    case ACPI_DMT_BUF10:
401    case ACPI_DMT_BUF16:
402    case ACPI_DMT_BUF128:
403    case ACPI_DMT_PCI_PATH:
404
405        Type = DT_FIELD_TYPE_BUFFER;
406        break;
407
408    case ACPI_DMT_GAS:
409    case ACPI_DMT_HESTNTFY:
410
411        Type = DT_FIELD_TYPE_INLINE_SUBTABLE;
412        break;
413
414    case ACPI_DMT_UNICODE:
415
416        Type = DT_FIELD_TYPE_UNICODE;
417        break;
418
419    case ACPI_DMT_UUID:
420
421        Type = DT_FIELD_TYPE_UUID;
422        break;
423
424    case ACPI_DMT_DEVICE_PATH:
425
426        Type = DT_FIELD_TYPE_DEVICE_PATH;
427        break;
428
429    case ACPI_DMT_LABEL:
430
431        Type = DT_FIELD_TYPE_LABEL;
432        break;
433
434    default:
435
436        Type = DT_FIELD_TYPE_INTEGER;
437        break;
438    }
439
440    return (Type);
441}
442
443
444/******************************************************************************
445 *
446 * FUNCTION:    DtGetBufferLength
447 *
448 * PARAMETERS:  Buffer              - List of integers,
449 *                                    for example "10 3A 4F 2E"
450 *
451 * RETURN:      Count of integer
452 *
453 * DESCRIPTION: Get length of bytes needed to store the integers
454 *
455 *****************************************************************************/
456
457UINT32
458DtGetBufferLength (
459    char                    *Buffer)
460{
461    UINT32                  ByteLength = 0;
462
463
464    while (*Buffer)
465    {
466        if (*Buffer == ' ')
467        {
468            ByteLength++;
469
470            while (*Buffer == ' ')
471            {
472                Buffer++;
473            }
474        }
475
476        Buffer++;
477    }
478
479    return (++ByteLength);
480}
481
482
483/******************************************************************************
484 *
485 * FUNCTION:    DtGetFieldLength
486 *
487 * PARAMETERS:  Field               - Current field
488 *              Info                - Data table info
489 *
490 * RETURN:      Field length
491 *
492 * DESCRIPTION: Get length of bytes needed to compile the field
493 *
494 * Note: This function must remain in sync with AcpiDmDumpTable.
495 *
496 *****************************************************************************/
497
498UINT32
499DtGetFieldLength (
500    DT_FIELD                *Field,
501    ACPI_DMTABLE_INFO       *Info)
502{
503    UINT32                  ByteLength = 0;
504    char                    *Value;
505
506
507    /* Length is based upon the opcode for this field in the info table */
508
509    switch (Info->Opcode)
510    {
511    case ACPI_DMT_FLAG0:
512    case ACPI_DMT_FLAG1:
513    case ACPI_DMT_FLAG2:
514    case ACPI_DMT_FLAG3:
515    case ACPI_DMT_FLAG4:
516    case ACPI_DMT_FLAG5:
517    case ACPI_DMT_FLAG6:
518    case ACPI_DMT_FLAG7:
519    case ACPI_DMT_FLAGS0:
520    case ACPI_DMT_FLAGS1:
521    case ACPI_DMT_FLAGS2:
522    case ACPI_DMT_FLAGS4:
523    case ACPI_DMT_LABEL:
524    case ACPI_DMT_EXTRA_TEXT:
525
526        ByteLength = 0;
527        break;
528
529    case ACPI_DMT_UINT8:
530    case ACPI_DMT_CHKSUM:
531    case ACPI_DMT_SPACEID:
532    case ACPI_DMT_ACCWIDTH:
533    case ACPI_DMT_IVRS:
534    case ACPI_DMT_MADT:
535    case ACPI_DMT_PMTT:
536    case ACPI_DMT_SRAT:
537    case ACPI_DMT_ASF:
538    case ACPI_DMT_HESTNTYP:
539    case ACPI_DMT_FADTPM:
540    case ACPI_DMT_EINJACT:
541    case ACPI_DMT_EINJINST:
542    case ACPI_DMT_ERSTACT:
543    case ACPI_DMT_ERSTINST:
544
545        ByteLength = 1;
546        break;
547
548    case ACPI_DMT_UINT16:
549    case ACPI_DMT_DMAR:
550    case ACPI_DMT_HEST:
551    case ACPI_DMT_PCI_PATH:
552
553        ByteLength = 2;
554        break;
555
556    case ACPI_DMT_UINT24:
557
558        ByteLength = 3;
559        break;
560
561    case ACPI_DMT_UINT32:
562    case ACPI_DMT_NAME4:
563    case ACPI_DMT_SLIC:
564    case ACPI_DMT_SIG:
565
566        ByteLength = 4;
567        break;
568
569    case ACPI_DMT_UINT40:
570
571        ByteLength = 5;
572        break;
573
574    case ACPI_DMT_UINT48:
575    case ACPI_DMT_NAME6:
576
577        ByteLength = 6;
578        break;
579
580    case ACPI_DMT_UINT56:
581    case ACPI_DMT_BUF7:
582
583        ByteLength = 7;
584        break;
585
586    case ACPI_DMT_UINT64:
587    case ACPI_DMT_NAME8:
588
589        ByteLength = 8;
590        break;
591
592    case ACPI_DMT_STRING:
593
594        Value = DtGetFieldValue (Field);
595        if (Value)
596        {
597            ByteLength = ACPI_STRLEN (Value) + 1;
598        }
599        else
600        {   /* At this point, this is a fatal error */
601
602            sprintf (MsgBuffer, "Expected \"%s\"", Info->Name);
603            DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, MsgBuffer);
604            return (0);
605        }
606        break;
607
608    case ACPI_DMT_GAS:
609
610        ByteLength = sizeof (ACPI_GENERIC_ADDRESS);
611        break;
612
613    case ACPI_DMT_HESTNTFY:
614
615        ByteLength = sizeof (ACPI_HEST_NOTIFY);
616        break;
617
618    case ACPI_DMT_BUFFER:
619
620        Value = DtGetFieldValue (Field);
621        if (Value)
622        {
623            ByteLength = DtGetBufferLength (Value);
624        }
625        else
626        {   /* At this point, this is a fatal error */
627
628            sprintf (MsgBuffer, "Expected \"%s\"", Info->Name);
629            DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, MsgBuffer);
630            return (0);
631        }
632        break;
633
634    case ACPI_DMT_BUF10:
635
636        ByteLength = 10;
637        break;
638
639    case ACPI_DMT_BUF16:
640    case ACPI_DMT_UUID:
641
642        ByteLength = 16;
643        break;
644
645    case ACPI_DMT_BUF128:
646
647        ByteLength = 128;
648        break;
649
650    case ACPI_DMT_UNICODE:
651
652        Value = DtGetFieldValue (Field);
653
654        /* TBD: error if Value is NULL? (as below?) */
655
656        ByteLength = (ACPI_STRLEN (Value) + 1) * sizeof(UINT16);
657        break;
658
659    default:
660
661        DtFatal (ASL_MSG_COMPILER_INTERNAL, Field, "Invalid table opcode");
662        return (0);
663    }
664
665    return (ByteLength);
666}
667
668
669/******************************************************************************
670 *
671 * FUNCTION:    DtSum
672 *
673 * PARAMETERS:  DT_WALK_CALLBACK:
674 *              Subtable            - Subtable
675 *              Context             - Unused
676 *              ReturnValue         - Store the checksum of subtable
677 *
678 * RETURN:      Status
679 *
680 * DESCRIPTION: Get the checksum of subtable
681 *
682 *****************************************************************************/
683
684static void
685DtSum (
686    DT_SUBTABLE             *Subtable,
687    void                    *Context,
688    void                    *ReturnValue)
689{
690    UINT8                   Checksum;
691    UINT8                   *Sum = ReturnValue;
692
693
694    Checksum = AcpiTbChecksum (Subtable->Buffer, Subtable->Length);
695    *Sum = (UINT8) (*Sum + Checksum);
696}
697
698
699/******************************************************************************
700 *
701 * FUNCTION:    DtSetTableChecksum
702 *
703 * PARAMETERS:  ChecksumPointer     - Where to return the checksum
704 *
705 * RETURN:      None
706 *
707 * DESCRIPTION: Set checksum of the whole data table into the checksum field
708 *
709 *****************************************************************************/
710
711void
712DtSetTableChecksum (
713    UINT8                   *ChecksumPointer)
714{
715    UINT8                   Checksum = 0;
716    UINT8                   OldSum;
717
718
719    DtWalkTableTree (Gbl_RootTable, DtSum, NULL, &Checksum);
720
721    OldSum = *ChecksumPointer;
722    Checksum = (UINT8) (Checksum - OldSum);
723
724    /* Compute the final checksum */
725
726    Checksum = (UINT8) (0 - Checksum);
727    *ChecksumPointer = Checksum;
728}
729
730
731/******************************************************************************
732 *
733 * FUNCTION:    DtSetTableLength
734 *
735 * PARAMETERS:  None
736 *
737 * RETURN:      None
738 *
739 * DESCRIPTION: Walk the subtables and set all the length fields
740 *
741 *****************************************************************************/
742
743void
744DtSetTableLength (
745    void)
746{
747    DT_SUBTABLE             *ParentTable;
748    DT_SUBTABLE             *ChildTable;
749
750
751    ParentTable = Gbl_RootTable;
752    ChildTable = NULL;
753
754    if (!ParentTable)
755    {
756        return;
757    }
758
759    DtSetSubtableLength (ParentTable);
760
761    while (1)
762    {
763        ChildTable = DtGetNextSubtable (ParentTable, ChildTable);
764        if (ChildTable)
765        {
766            if (ChildTable->LengthField)
767            {
768                DtSetSubtableLength (ChildTable);
769            }
770
771            if (ChildTable->Child)
772            {
773                ParentTable = ChildTable;
774                ChildTable = NULL;
775            }
776            else
777            {
778                ParentTable->TotalLength += ChildTable->TotalLength;
779                if (ParentTable->LengthField)
780                {
781                    DtSetSubtableLength (ParentTable);
782                }
783            }
784        }
785        else
786        {
787            ChildTable = ParentTable;
788
789            if (ChildTable == Gbl_RootTable)
790            {
791                break;
792            }
793
794            ParentTable = DtGetParentSubtable (ParentTable);
795
796            ParentTable->TotalLength += ChildTable->TotalLength;
797            if (ParentTable->LengthField)
798            {
799                DtSetSubtableLength (ParentTable);
800            }
801        }
802    }
803}
804
805
806/******************************************************************************
807 *
808 * FUNCTION:    DtWalkTableTree
809 *
810 * PARAMETERS:  StartTable          - Subtable in the tree where walking begins
811 *              UserFunction        - Called during the walk
812 *              Context             - Passed to user function
813 *              ReturnValue         - The return value of UserFunction
814 *
815 * RETURN:      None
816 *
817 * DESCRIPTION: Performs a depth-first walk of the subtable tree
818 *
819 *****************************************************************************/
820
821void
822DtWalkTableTree (
823    DT_SUBTABLE             *StartTable,
824    DT_WALK_CALLBACK        UserFunction,
825    void                    *Context,
826    void                    *ReturnValue)
827{
828    DT_SUBTABLE             *ParentTable;
829    DT_SUBTABLE             *ChildTable;
830
831
832    ParentTable = StartTable;
833    ChildTable = NULL;
834
835    if (!ParentTable)
836    {
837        return;
838    }
839
840    UserFunction (ParentTable, Context, ReturnValue);
841
842    while (1)
843    {
844        ChildTable = DtGetNextSubtable (ParentTable, ChildTable);
845        if (ChildTable)
846        {
847            UserFunction (ChildTable, Context, ReturnValue);
848
849            if (ChildTable->Child)
850            {
851                ParentTable = ChildTable;
852                ChildTable = NULL;
853            }
854        }
855        else
856        {
857            ChildTable = ParentTable;
858            if (ChildTable == Gbl_RootTable)
859            {
860                break;
861            }
862
863            ParentTable = DtGetParentSubtable (ParentTable);
864
865            if (ChildTable->Peer == StartTable)
866            {
867                break;
868            }
869        }
870    }
871}
872
873
874/******************************************************************************
875 *
876 * FUNCTION:    DtFreeFieldList
877 *
878 * PARAMETERS:  None
879 *
880 * RETURN:      None
881 *
882 * DESCRIPTION: Free the field list
883 *
884 *****************************************************************************/
885
886void
887DtFreeFieldList (
888    void)
889{
890    DT_FIELD                *Field = Gbl_FieldList;
891    DT_FIELD                *NextField;
892
893
894    /* Walk and free entire field list */
895
896    while (Field)
897    {
898        NextField = Field->Next; /* Save link */
899
900        if (!(Field->Flags & DT_FIELD_NOT_ALLOCATED))
901        {
902            ACPI_FREE (Field->Name);
903            ACPI_FREE (Field->Value);
904        }
905
906        ACPI_FREE (Field);
907        Field = NextField;
908    }
909}
910