/* * Type Printing for X11 protocol * * James Peterson, 1988 * * Copyright (C) 1988 MCC * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of MCC not be used in * advertising or publicity pertaining to distribution of the software without * specific, written prior permission. MCC makes no * representations about the suitability of this software for any purpose. It * is provided "as is" without express or implied warranty. * * MCC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL MCC BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. * */ /* * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ #include "scope.h" #include "x11.h" /* For each of the types we need a way to print that type. Types are of varieties: (1) BUILTIN -- we have a separate routine to interpret and print each built-in type. (2) ENUMERATED, SET -- we have one routine which prints, given the data and the list of values. (3) RECORDS -- a separate routine for each to print each field. */ /* ************************************************************ */ /* */ /* */ /* ************************************************************ */ /* print representation of a character for debugging */ static const char * printrep(unsigned short c) { static char pr[8]; if (c < 32) { /* control characters */ pr[0] = '^'; pr[1] = c + 64; pr[2] = '\0'; } else if (c < 127) { /* printing characters */ pr[0] = (char) c; pr[1] = '\0'; } else if (c == 127) return (""); else if (c <= 0377) { /* upper 128 codes from 128 to 255; print as \ooo - octal */ pr[0] = '\\'; pr[3] = '0' + (c & 7); c = c >> 3; pr[2] = '0' + (c & 7); c = c >> 3; pr[1] = '0' + (c & 3); pr[4] = '\0'; } else { /* very large number -- print as 0xffff - 4 digit hex */ snprintf(pr, sizeof(pr), "0x%04x", c); } return (pr); } /* ************************************************************ */ /* */ /* */ /* ************************************************************ */ /* we use indentation for two purposes: (1) To show substructure of records inside records ... (2) To separate the bytes from the client (on the left) from those from the server (on the right). Each indention level is one tab (8 spaces). */ #define MaxIndent 10 char Leader[MaxIndent + 1]; static short CurrentLevel = 0; void SetIndentLevel(short which) { short i; if (which > MaxIndent) which = MaxIndent; if (which < 0) which = 0; if (which == CurrentLevel) return; /* set the indent level to */ /* -> set the Print Leader to tabs */ for (i = 0; i < which; i++) Leader[i] = '\t'; Leader[which] = '\0'; CurrentLevel = which; } static void ModifyIndentLevel(short amount) { SetIndentLevel(CurrentLevel + amount); } static short SizeofLeader(void) { return (CurrentLevel * 8); } /* ************************************************************ */ /* */ /* */ /* ************************************************************ */ /* if we want verbose enough output, we will dump the buffer in hex */ void DumpItem(const char *name, FD fd, const unsigned char *buf, long n) { if (n == 0) return; fprintf(stdout, "%s%20s (fd %d): ", Leader, name, fd); DumpHexBuffer(buf, n); fprintf(stdout, "\n"); } /* ************************************************************ */ /* */ /* */ /* ************************************************************ */ int PrintINT8(const unsigned char *buf) { /* print a INT8 -- 8-bit signed integer */ short n = IByte(buf); if (n > 127) n = 256 - n; fprintf(stdout, "%d", n); return 1; } int PrintINT16(const unsigned char *buf) { /* print a INT16 -- 16-bit signed integer */ long n = IShort(buf); if (n > 32767) n = 65536 - n; fprintf(stdout, "%ld", n); return 2; } int PrintINT32(const unsigned char *buf) { /* print a INT32 -- 32-bit signed integer */ long n = ILong(buf); fprintf(stdout, "%ld", n); return 4; } /* ************************************************************ */ int PrintCARD8(const unsigned char *buf) { /* print a CARD8 -- 8-bit unsigned integer */ unsigned short n = IByte(buf); fprintf(stdout, "%02x", (unsigned) (n & 0xff)); return 1; } int PrintCARD16(const unsigned char *buf) { /* print a CARD16 -- 16-bit unsigned integer */ unsigned long n = IShort(buf); fprintf(stdout, "%04x", (unsigned) (n & 0xffff)); return 1; } int PrintCARD32(const unsigned char *buf) { /* print a CARD32 -- 32-bit unsigned integer */ unsigned long n = ILong(buf); fprintf(stdout, "%08lx", n); return (4); } /* ************************************************************ */ int PrintBYTE(const unsigned char *buf) { /* print a BYTE -- 8-bit value */ short n = IByte(buf); fprintf(stdout, "%02x", n); return (1); } int PrintCHAR8(const unsigned char *buf) { /* print a CHAR8 -- 8-bit character */ unsigned short n = IByte(buf); fprintf(stdout, "%s", printrep(n)); return (1); } int PrintSTRING16(const unsigned char *buf) { /* print a CHAR2B -- 16-bit character which is never byte-swapped */ unsigned short n = IChar2B(buf); fprintf(stdout, "%s", printrep(n)); return 2 + n; } int PrintSTR(const unsigned char *buf) { /* STR have the length (1 byte) then a string of CHAR8 */ short n; short i; n = IByte(buf++); for (i = 0; i < n; i++) fprintf(stdout, "%s", printrep(buf[i])); return (n + 1); } /* ************************************************************ */ int PrintWINDOW(const unsigned char *buf) { /* print a WINDOW -- CARD32 plus 0 = None */ long n = ILong(buf); if (n == 0) fprintf(stdout, "None"); else fprintf(stdout, "WIN %08lx", n); return (4); } int PrintWINDOWD(const unsigned char *buf) { /* print a WINDOWD -- CARD32 plus 0 = PointerWindow, 1 = InputFocus */ long n = ILong(buf); if (n == 0) fprintf(stdout, "PointerWindow"); else if (n == 1) fprintf(stdout, "InputFocus"); else (void) PrintWINDOW(buf); return 4; } int PrintWINDOWNR(const unsigned char *buf) { /* print a WINDOWNR -- CARD32 plus 0 = None, 1 = PointerRoot */ long n = ILong(buf); if (n == 0) fprintf(stdout, "None"); else if (n == 1) fprintf(stdout, "PointerRoot"); else (void) PrintWINDOW(buf); return 4; } int PrintPIXMAP(const unsigned char *buf) { /* print a PIXMAP -- CARD32 plus 0 = None */ long n = ILong(buf); if (n == 0) fprintf(stdout, "None"); else fprintf(stdout, "PXM %08lx", n); return 4; } int PrintPIXMAPNPR(const unsigned char *buf) { /* print a PIXMAPNPR -- CARD32 plus 0 = None, 1 = ParentRelative */ long n = ILong(buf); if (n == 0) fprintf(stdout, "None"); else if (n == 1) fprintf(stdout, "ParentRelative"); else PrintPIXMAP(buf); return 4; } int PrintPIXMAPC(const unsigned char *buf) { /* print a PIXMAPC -- CARD32 plus 0 = CopyFromParent */ long n = ILong(buf); if (n == 0) fprintf(stdout, "CopyFromParent"); else PrintPIXMAP(buf); return 4; } int PrintCURSOR(const unsigned char *buf) { /* print a CURSOR -- CARD32 plus 0 = None */ long n = ILong(buf); if (n == 0) fprintf(stdout, "None"); else fprintf(stdout, "CUR %08lx", n); return 4; } int PrintFONT(const unsigned char *buf) { /* print a FONT -- CARD32 plus 0 = None */ long n = ILong(buf); if (n == 0) fprintf(stdout, "None"); else fprintf(stdout, "FNT %08lx", n); return 4; } int PrintGCONTEXT(const unsigned char *buf) { /* print a GCONTEXT -- CARD32 */ long n = ILong(buf); fprintf(stdout, "GXC %08lx", n); return 4; } int PrintCOLORMAP(const unsigned char *buf) { /* print a COLORMAP -- CARD32 plus 0 = None */ long n = ILong(buf); if (n == 0) fprintf(stdout, "None"); else fprintf(stdout, "CMP %08lx", n); return (4); } int PrintCOLORMAPC(const unsigned char *buf) { /* print a COLORMAPC -- CARD32 plus 0 = CopyFromParent */ long n = ILong(buf); if (n == 0) fprintf(stdout, "CopyFromParent"); else (void) PrintCOLORMAP(buf); return 4; } int PrintDRAWABLE(const unsigned char *buf) { /* print a DRAWABLE -- CARD32 */ long n = ILong(buf); fprintf(stdout, "DWB %08lx", n); return 4; } int PrintFONTABLE(const unsigned char *buf) { /* print a FONTABLE -- CARD32 */ long n = ILong(buf); fprintf(stdout, "FTB %08lx", n); return 4; } /* ************************************************************ */ /* for atoms, we print the built-in atoms, as well as any user defined ones we've captured during this session. */ int PrintATOM(const unsigned char *buf) { /* print a ATOM -- CARD32 plus 0 = None */ long n = ILong(buf); const char *name = FindAtomName(n); if (name != NULL) { if (Verbose > 1) fprintf(stdout, "ATM %08lx <%s>", n, name); else fprintf(stdout, "<%s>", name); } else fprintf(stdout, "ATM %08lx", n); return (4); } int PrintATOMT(const unsigned char *buf) { /* print a ATOMT -- CARD32 plus 0 = AnyPropertyType */ long n = ILong(buf); if (n == 0) fprintf(stdout, "AnyPropertyType"); else (void) PrintATOM(buf); return 4; } int PrintVISUALID(const unsigned char *buf) { /* print a VISUALID -- CARD32 plus 0 = None */ long n = ILong(buf); if (n == 0) fprintf(stdout, "None"); else fprintf(stdout, "VIS %08lx", n); return 4; } int PrintVISUALIDC(const unsigned char *buf) { /* print a VISUALIDC -- CARD32 plus 0 = CopyFromParent */ long n = ILong(buf); if (n == 0) fprintf(stdout, "CopyFromParent"); else PrintVISUALID(buf); return 4; } int PrintTIMESTAMP(const unsigned char *buf) { /* print a TIMESTAMP -- CARD32 plus 0 as the current time */ long n = ILong(buf); if (n == 0) fprintf(stdout, "CurrentTime"); else fprintf(stdout, "TIM %08lx", n); return 4; } int PrintRESOURCEID(const unsigned char *buf) { /* print a RESOURCEID -- CARD32 plus 0 = AllTemporary */ long n = ILong(buf); if (n == 0) fprintf(stdout, "AllTemporary"); else fprintf(stdout, "RID %08lx", n); return 4; } int PrintKEYSYM(const unsigned char *buf) { /* print a KEYSYM -- CARD32 */ long n = ILong(buf); fprintf(stdout, "KYS %08lx", n); return (4); } int PrintKEYCODE(const unsigned char *buf) { /* print a KEYCODE -- CARD8 */ unsigned short n = IByte(buf); fprintf(stdout, "%d (%s)", n, printrep(n)); return (1); } int PrintKEYCODEA(const unsigned char *buf) { /* print a KEYCODEA -- CARD8 plus 0 = AnyKey */ long n = IByte(buf); if (n == 0) fprintf(stdout, "AnyKey"); else (void) PrintKEYCODE(buf); return 1; } int PrintBUTTON(const unsigned char *buf) { /* print a BUTTON -- CARD8 */ unsigned short n = IByte(buf); fprintf(stdout, "%d (%s)", n, printrep(n)); return 1; } int PrintBUTTONA(const unsigned char *buf) { /* print a BUTTONA -- CARD8 plus 0 = AnyButton */ long n = IByte(buf); if (n == 0) fprintf(stdout, "AnyButton"); else PrintBUTTON(buf); return 1; } /* this is an interesting cheat -- we call DecodeEvent to print an event */ /* should work, but its never been tried */ int PrintEVENTFORM(const unsigned char *buf) { /* print an EVENT_FORM -- event format */ DecodeEvent(-1, buf, (long) -1); return 32; } int PrintEVENT(const unsigned char *buf) { uint8_t n = IByte(buf); long e = (long) (n & 0x7f); struct ValueListEntry *p; p = TD[EVENT].ValueList; while (p != NULL && p->Value != e) p = p->Next; if (p != NULL) fprintf(stdout, "%s", p->Name); else fprintf(stdout, "**INVALID** (%d)", n); if (n & 0x80) fprintf(stdout, "\n%s%20s: %s", Leader, "source", "SendEvent"); return 1; } /* ************************************************************ */ int PrintENUMERATED(const unsigned char *buf, short length, struct ValueListEntry *ValueList) { long n; struct ValueListEntry *p; if (length == 1) n = IByte(buf); else if (length == 2) n = IShort(buf); else n = ILong(buf); p = ValueList; while (p != NULL && p->Value != n) p = p->Next; if (p != NULL) fprintf(stdout, "%s", p->Name); else fprintf(stdout, "**INVALID** (%ld)", n); return length; } /* ************************************************************ */ int PrintSET(const unsigned char *buf, short length, struct ValueListEntry *ValueList) { unsigned long n; struct ValueListEntry *p; Boolean MatchesAll = false; Boolean FoundOne = false; if (length == 1) n = IByte(buf); else if (length == 2) n = IShort(buf); else n = ILong(buf); if (n != 0) { /* first check if the value matches ALL of the bits. */ MatchesAll = true; for (p = ValueList; MatchesAll && (p != NULL); p = p->Next) { if ((p->Value & n) == 0) MatchesAll = false; } if (!MatchesAll) /* if it matches some, but not all, print only those it matches */ for (p = ValueList; p != NULL; p = p->Next) { if ((p->Value & n) != 0) { if (FoundOne) fprintf(stdout, " | "); fprintf(stdout, "%s", p->Name); FoundOne = true; } } } if (MatchesAll) fprintf(stdout, ""); else if (!FoundOne) fprintf(stdout, "0"); return length; } /* ************************************************************ */ /* */ /* */ /* ************************************************************ */ void PrintField(const unsigned char *buf, short start, short length, short FieldType, const char *name) { if (Verbose == 0) return; if (length == 0) return; fprintf(stdout, "%s%20s: ", Leader, name); if (debuglevel & 8) DumpHexBuffer(&(buf[start]), (long) length); switch (TD[FieldType].Type) { case BUILTIN: (*TD[FieldType].PrintProc) (&buf[start]); break; case ENUMERATED: PrintENUMERATED(&buf[start], length, TD[FieldType].ValueList); break; case SET: PrintSET(&buf[start], length, TD[FieldType].ValueList); break; case RECORD: ModifyIndentLevel(1); fprintf(stdout, "\n"); if (Verbose < 3) return; (*TD[FieldType].PrintProc) (&buf[start]); ModifyIndentLevel(-1); break; } fprintf(stdout, "\n"); fflush(stdout); } /* ************************************************************ */ /* */ /* */ /* ************************************************************ */ /* print a list of things. The things are of type . They start at . There are things in the list */ long PrintList(const unsigned char *buf, long number, short ListType, const char *name) { long n; long i; long sum; if (Verbose == 0) return (0); if (number == 0) return (0); fprintf(stdout, "%s%20s: (%ld)\n", Leader, name, number); if (Verbose < 2) return (0); ModifyIndentLevel(1); sum = 0; for (i = 0; i < number; i++) { switch (TD[ListType].Type) { case BUILTIN: n = (*TD[ListType].PrintProc) (buf); break; case RECORD: n = (*TD[ListType].PrintProc) (buf); break; default: fprintf(stdout, "**INVALID**"); n = 0; break; } buf = buf + n; sum = sum + n; fprintf(stdout, "%s---\n", Leader); } ModifyIndentLevel(-1); return (sum); } /* ************************************************************ */ /* */ /* */ /* ************************************************************ */ /* print a list of STRs. Similar to PrintList They start at . There are things in the list */ long PrintListSTR(const unsigned char *buf, long number, const char *name) { long n; long i; long sum; if (number == 0) return (0); fprintf(stdout, "%s%20s: (%ld)\n", Leader, name, number); if (Verbose < 2) return (0); ModifyIndentLevel(1); sum = 0; for (i = 0; i < number; i++) { fprintf(stdout, "%s", Leader); n = PrintSTR(buf); buf = buf + n; sum = sum + n; fprintf(stdout, "\n"); } ModifyIndentLevel(-1); return (sum); } /* ************************************************************ */ /* */ /* */ /* ************************************************************ */ int PrintBytes(const unsigned char *buf, long number, const char *name) { /* print a list of BYTE -- 8-bit character */ long i; short column; if (number == 0) return (0); fprintf(stdout, "%s%20s: ", Leader, name); column = SizeofLeader() + 25; for (i = 0; i < number; i++) { if (column > 80) { if (Verbose < 2) break; fprintf(stdout, "\n%s%20s: ", Leader, ""); column = SizeofLeader() + 25; } fprintf(stdout, "%02x ", ((unsigned int) buf[i])); column += 3; } fprintf(stdout, "\n"); return (number); } /* ************************************************************ */ /* */ /* */ /* ************************************************************ */ /* print a String of CHAR8 -- 8-bit characters */ int PrintString8(const unsigned char *buf, int number, const char *name) { short i; if (number == 0) return (0); fprintf(stdout, "%s%20s: \"", Leader, name); for (i = 0; i < number; i++) fprintf(stdout, "%s", printrep(buf[i])); fprintf(stdout, "\"\n"); return (number); } /* print a String of CHAR16 -- 16-bit characters */ int PrintString16(const unsigned char *buf, int number, const char *name) { long i; unsigned short c; if (number == 0) return (0); fprintf(stdout, "%s%20s: \"", Leader, name); for (i = 0; i < number * 2; i += 2) { c = IChar2B(&buf[i]); fprintf(stdout, "%s", printrep(c)); } fprintf(stdout, "\"\n"); return (number); } void PrintTString8(const unsigned char *buf, long number, const char *name) { long i; int off; if (number == 0) return; off = 0; if (TranslateText) off = 0x20; fprintf(stdout, "%s%20s: \"", Leader, name); for (i = 0; i < number; i++) fprintf(stdout, "%s", printrep(buf[i] + off)); fprintf(stdout, "\"\n"); } /* print a String of CHAR2B -- 16-bit characters */ void PrintTString16(const unsigned char *buf, long number, const char *name) { long i; unsigned short c; int off; if (number == 0) return; off = 0; if (TranslateText) off = 0x20; fprintf(stdout, "%s%20s: \"", Leader, name); for (i = 0; i < number * 2; i += 2) { c = IChar2B(&buf[i]); fprintf(stdout, "%s", printrep(c + off)); } fprintf(stdout, "\"\n"); } /* ************************************************************ */ /* */ /* */ /* ************************************************************ */ /* A Value List is two things: (1) A controlling bitmask. For each one bit in the control, a value is in the list. (2) A list of values. */ void PrintValues(const unsigned char *control, int clength, int ctype, const unsigned char *values, const char *name) { long cmask; struct ValueListEntry *p; /* first get the control mask */ if (clength == 1) cmask = IByte(control); else if (clength == 2) cmask = IShort(control); else cmask = ILong(control); /* now if it is zero, ignore and return */ if (cmask == 0) return; /* there are bits in the controlling bitmask, figure out which */ /* the ctype is a set type, so this code is similar to PrintSET */ fprintf(stdout, "%s%20s:\n", Leader, name); ModifyIndentLevel(1); for (p = TD[ctype].ValueList; p != NULL; p = p->Next) { if ((p->Value & cmask) != 0) { short m; if (littleEndian) m = 0; else m = 4 - p->Length; PrintField(values, m, p->Length, p->Type, p->Name); values += 4; } } ModifyIndentLevel(-1); } /* ************************************************************ */ /* */ /* */ /* ************************************************************ */ /* PolyText8 and PolyText16 take lists of characters with possible font changes in them. */ void PrintTextList8(const unsigned char *buf, int length, const char *name) { short n; fprintf(stdout, "%s%20s:\n", Leader, name); while (length > 1) { n = IByte(&buf[0]); if (n != 255) { PrintField(buf, 1, 1, INT8, "delta"); PrintTString8(&buf[2], (long) n, "text item 8 string"); buf += n + 2; length -= n + 2; } else { PrintField(buf, 1, 4, FONT, "font-shift-id"); buf += 4; length -= 4; } } } void PrintTextList16(const unsigned char *buf, int length, const char *name) { short n; fprintf(stdout, "%s%20s:\n", Leader, name); while (length > 1) { n = IByte(&buf[0]); if (n != 255) { PrintField(buf, 1, 1, INT8, "delta"); PrintTString16(&buf[2], (long) n, "text item 16 string"); buf += n + 2; length -= n + 2; } else { PrintField(buf, 1, 4, FONT, "font-shift-id"); buf += 4; length -= 4; } } } /* ************************************************************ */ /* */ /* */ /* ************************************************************ */ /* Several extensions have grown property requests mimicing the core protocol Window properties, and share this code for printing lists of property values */ int PrintPropertyValues(const unsigned char *buf, uint32_t type /* atom */, uint8_t unit, uint32_t num, const char *name) { short fieldType = 0; switch (type) { case 4: /* XA_ATOM */ fieldType = ATOM; break; case 6: /* XA_CARDINAL */ switch (unit) { case 4: fieldType = CARD32; break; case 2: fieldType = CARD16; break; case 1: fieldType = CARD8; break; default: goto rawbytes; } break; case 19: /* XA_INTEGER */ switch (unit) { case 4: fieldType = INT32; break; case 2: fieldType = INT16; break; case 1: fieldType = INT8; break; default: goto rawbytes; } break; case 31: /* XA_STRING */ return PrintString8(buf, num * unit, name); case 33: /* XA_WINDOW */ fieldType = WINDOW; break; default: /* Fall through to check for known non-builtin types below */ break; } if (fieldType != 0) { if (num == 1) { PrintField(buf, 0, unit, fieldType, name); return unit; } else return PrintList(buf, num, fieldType, name); } else { const char *typename = FindAtomName(type); if (typename) { if (strcmp(typename, "UTF8_STRING") == 0) { if (IsUTF8locale) return PrintString8(buf, num * unit, name); else goto rawbytes; } } } rawbytes: /* When all else fails, print raw bytes */ return PrintBytes(buf, num * unit, name); } /* ************************************************************ */ /* */ /* */ /* ************************************************************ */ #define MAXline 78 void DumpHexBuffer(const unsigned char *buf, long n) { long i; short column; char h[6]; /* one hex or octal character */ column = 27 + SizeofLeader(); for (i = 0; i < n; i++) { /* get the hex representations */ snprintf(h, sizeof(h), "%02x", (0xff & buf[i])); /* check if these characters will fit on this line */ if ((column + strlen(h) + 1) > MAXline) { /* line will be too long -- print it */ fprintf(stdout, "\n"); column = 0; } fprintf(stdout, "%s ", h); column += 3; } } void PrintValueRec(uint32_t key, uint32_t cmask, short ctype) { unsigned char *values; struct ValueListEntry *p; ValuePtr value; value = GetValueRec(key); if (!value) return; values = (unsigned char *) value->values; /* now if it is zero, ignore and return */ if (cmask == 0) return; /* there are bits in the controlling bitmask, figure out which */ /* the ctype is a set type, so this code is similar to PrintSET */ ModifyIndentLevel(1); for (p = TD[ctype].ValueList; p != NULL; p = p->Next) { if ((p->Value & cmask) != 0) { short m; if (littleEndian) m = 0; else m = 4 - p->Length; PrintField(values, m, p->Length, p->Type, p->Name); } values += 4; } ModifyIndentLevel(-1); }