X-Authentication-Warning: delorie.com: mailnull set sender to djgpp-workers-bounces using -f Date: Sun, 10 Feb 2002 12:23:46 +0000 From: "Richard Dawe" Sender: rich AT phekda DOT freeserve DOT co DOT uk To: djgpp-workers AT delorie DOT com X-Mailer: Emacs 21.0.98 (via feedmail 8.3.emacs20_6 I) and Blat ver 1.8.6 Subject: mkdoc patch, try 4 Message-Id: Reply-To: djgpp-workers AT delorie DOT com Hello. Below is the fourth version of the patch to mkdoc to make it show portability information in a less ambiguous manner and also to allow support for multiple versions of standards (e.g. C89 vs. C99). Here is a recap of the problem: @portability !ansi, posix produces the following output: Not ANSI, POSIX which is ambiguous. The patch allows you to do: @portability ansi-c89, !ansi-c99 producing: ANSI/ISO C C89, not C99 If you do: @portability ansi you get: ANSI/ISO C C89, C99 To list all portability targets, run mkdoc with the '-l' or '--list-targets' switch. Changes from the previous patch: * added the new POSIX standard - 1003.1-2001; * added a changelog entry. This patch does not support: * portability types defined on the fly (suggested by DJ); * multi-line portability notes. OK to commit? Once the patch is committed, I'll go through all the functions added to DJGPP in CVS, to check that they have the correct portability information (e.g. snprintf). I can't check the POSIX functions, since I don't have a copy of 1003.2. Maybe someone else can do those? Thanks, bye, Rich =] Index: src/mkdoc/mkdoc.cc =================================================================== RCS file: /cvs/djgpp/djgpp/src/mkdoc/mkdoc.cc,v retrieving revision 1.4 diff -p -c -3 -r1.4 mkdoc.cc *** src/mkdoc/mkdoc.cc 1999/12/14 12:01:35 1.4 --- src/mkdoc/mkdoc.cc 2002/02/10 12:13:18 *************** *** 1,3 **** --- 1,5 ---- + /* Copyright (C) 2002 DJ Delorie, see COPYING.DJ for details */ + /* Copyright (C) 2000 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1999 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1998 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1997 DJ Delorie, see COPYING.DJ for details */ *************** int count_nodes = 0; *** 29,47 **** typedef void (*TFunc)(Node *); - #define NUM_PORT_TARGETS 2 - #define PORT_UNKNOWN 0 #define PORT_NO 1 #define PORT_PARTIAL 2 #define PORT_YES 3 - - /* Tokens for use in .txh files */ - char *port_target[NUM_PORT_TARGETS] = { "ansi", "posix" }; - /* Strings to output in .txi files */ - char *port_target_string[NUM_PORT_TARGETS] = { "ANSI", "POSIX" }; struct Tree { TreeNode *nodes; --- 31,97 ---- typedef void (*TFunc)(Node *); + #define PORT_TARGET_NONE 0x00 + /* ANSI/ISO C */ + #define PORT_TARGET_ANSI_C89 0x10 + #define PORT_TARGET_ANSI_C99 0x11 + /* POSIX */ + #define PORT_TARGET_POSIX_1003_2_1992 0x20 + #define PORT_TARGET_POSIX_1003_1_2001 0x21 + /* Single Unix Specification(s) (SUS) */ + #define PORT_TARGET_UNIX_98 0x30 #define PORT_UNKNOWN 0 #define PORT_NO 1 #define PORT_PARTIAL 2 #define PORT_YES 3 + /* This structure is used to store both the default information about a + * particular porting target and the information parsed from the texinfo. + * For the default case, complete specifies the default value for this + * qualifier if the prefix is matched, but the suffix is not. */ + typedef struct { + char *suffix_token; /* Suffix token used in texinfo, e.g. 'c89' */ + char *suffix_name; /* Portability qualifier name, e.g. C89 */ + int target; /* One of PORT_TARGET_* */ + int complete; /* One of PORT_UNKNOWN, etc. */ + } PortQualifier; + + #define MAX_PORT_QUALIFIERS 2 + + typedef struct { + char *prefix_token; /* Token used in texinfo, e.g. 'ansi' */ + char *prefix_name; /* Actual textual name for token, e.g. ANSI/ISO C */ + PortQualifier pq[MAX_PORT_QUALIFIERS]; + } PortInfo; + + #define NUM_PORT_TARGETS 3 + + PortInfo port_target[] = { + /* ANSI/ISO C */ + { "ansi", "ANSI/ISO C", + { + { "c89", "C89", PORT_TARGET_ANSI_C89, PORT_YES }, + { "c99", "C99", PORT_TARGET_ANSI_C99, PORT_YES } + } + }, + /* POSIX */ + { "posix", "POSIX", + { + { "1003.2-1992", "1003.2-1992", + PORT_TARGET_POSIX_1003_2_1992, PORT_YES }, + { "1003.1-2001", "1003.1-2001", + PORT_TARGET_POSIX_1003_1_2001, PORT_YES } + } + }, + /* SUSv2 */ + { "unix", "Unix", + { + { "98", "Unix98", PORT_TARGET_UNIX_98, PORT_UNKNOWN }, + { 0 } + } + } + }; struct Tree { TreeNode *nodes; *************** struct Line { *** 59,65 **** struct PortNote { struct PortNote *next; ! int target; int number; char *note; }; --- 109,116 ---- struct PortNote { struct PortNote *next; ! PortInfo *pi; ! PortQualifier *pq; int number; char *note; }; *************** struct Node { *** 73,79 **** Line *lastline; Tree subnodes; char *filename; ! int port_info[NUM_PORT_TARGETS]; PortNote *port_notes; PortNote *last_port_note; Node(char *name, char *cat); --- 124,130 ---- Line *lastline; Tree subnodes; char *filename; ! PortInfo port_info[NUM_PORT_TARGETS]; PortNote *port_notes; PortNote *last_port_note; Node(char *name, char *cat); *************** Node::Node(char *Pname, char *Pcat) *** 107,113 **** cat = strdup(Pcat); lines = 0; lastline = 0; ! for (int i = 0; i < NUM_PORT_TARGETS; i++) port_info[i] = PORT_UNKNOWN; port_notes = NULL; last_port_note = NULL; } --- 158,165 ---- cat = strdup(Pcat); lines = 0; lastline = 0; ! for (int i = 0; i < NUM_PORT_TARGETS; i++) ! bzero(&port_info[i], sizeof(port_info[i])); port_notes = NULL; last_port_note = NULL; } *************** void *** 151,159 **** Node::read_portability_note(char *str) { char *work_str = strdup (str); ! char *s = work_str; char *target; ! int targ_num; while (isspace(*s)) s++; target = s; --- 203,211 ---- Node::read_portability_note(char *str) { char *work_str = strdup (str); ! char *s = work_str, *x = NULL; char *target; ! int i, j; while (isspace(*s)) s++; target = s; *************** Node::read_portability_note(char *str) *** 162,182 **** while (isspace(*s)) s++; dj_strlwr (target); ! for (targ_num = 0; targ_num < NUM_PORT_TARGETS; targ_num++) ! if (!strcmp (target, port_target[targ_num])) break; ! if (targ_num == NUM_PORT_TARGETS) ! { error ("unrecognised portability note target `%s' ignored.\n", target); ! } ! else ! { PortNote *p = new PortNote; p->next = NULL; p->number = 0; ! p->target = targ_num; p->note = strdup (""); if (port_notes) { last_port_note->next = p; --- 214,255 ---- while (isspace(*s)) s++; dj_strlwr (target); ! for (i = 0; i < NUM_PORT_TARGETS; i++) { ! if ( (strlen (target) >= strlen (port_target[i].prefix_token)) ! && !strncmp (target, port_target[i].prefix_token, ! strlen (port_target[i].prefix_token))) { ! /* If matched, check that the next character is either: null, a dash ! * (to indicate a qualifier) or null. */ ! x = target + strlen (port_target[i].prefix_token); ! if ((*x == '\0') || (*x == '-') || isspace((int) *x)) ! break; ! } ! } ! if (i == NUM_PORT_TARGETS) { error ("unrecognised portability note target `%s' ignored.\n", target); ! } else { PortNote *p = new PortNote; p->next = NULL; p->number = 0; ! p->pi = &port_target[i]; ! p->pq = NULL; p->note = strdup (""); + + /* Try to match the portability note to a portability qualifier. */ + x = target + strlen (p->pi->prefix_token); + if (*x == '-') + x++; + + for (j = 0; j < MAX_PORT_QUALIFIERS; j++) { + if (p->pi->pq[j].suffix_token == NULL) continue; + if (!strcmp (x, p->pi->pq[j].suffix_token)) break; + } + if (j < MAX_PORT_QUALIFIERS) + p->pq = &p->pi->pq[j]; + + /* Attach portability note to note chain. */ if (port_notes) { last_port_note->next = p; *************** void *** 196,207 **** Node::read_portability(char *str) { char *targets = dj_strlwr (strdup (str)); ! char *x, *target = targets; ! int type,i; while (isspace (*target)) target++; while (*target) { - type = PORT_YES; if (*target == '~') { --- 269,279 ---- Node::read_portability(char *str) { char *targets = dj_strlwr (strdup (str)); ! char *p = NULL, *x = NULL, *target = targets; ! int type, i, j; while (isspace (*target)) target++; while (*target) { type = PORT_YES; if (*target == '~') { *************** Node::read_portability(char *str) *** 216,228 **** for (x = target; *x && !isspace(*x) && (*x != ','); x++); if (*x) *x++ = 0; ! for (i = 0; i < NUM_PORT_TARGETS; i++) ! if (!strcmp (target, port_target[i])) break; ! if (i < NUM_PORT_TARGETS) ! port_info[i] = type; ! else error ("unrecognised portability target `%s' ignored.\n", target); target = x; while (isspace (*target)) target++; --- 288,343 ---- for (x = target; *x && !isspace(*x) && (*x != ','); x++); if (*x) *x++ = 0; ! for (i = 0; i < NUM_PORT_TARGETS; i++) { ! if ( (strlen (target) >= strlen (port_target[i].prefix_token)) ! && !strncmp (target, port_target[i].prefix_token, ! strlen (port_target[i].prefix_token))) { ! /* If matched, check that the next character is either: null, a dash ! * (to indicate a qualifier) or null. */ ! p = target + strlen (port_target[i].prefix_token); ! if ((*p == '\0') || (*p == '-') || isspace((int) *p)) ! break; ! } ! } ! if (i < NUM_PORT_TARGETS) { ! /* Now match the portability qualifier, if present. */ ! p = target + strlen (port_target[i].prefix_token); ! ! if (port_info[i].prefix_name == NULL) { ! /* Copy default portability information to uninitialised port ! * info, qualifier list. */ ! memcpy(&port_info[i], &port_target[i], sizeof(port_target[i])); ! } ! ! ! if (*p == '-') { ! /* A qualifier is present, so set the portability type for just ! * this qualifier. */ ! p++; ! ! for (j = 0; j < MAX_PORT_QUALIFIERS; j++) { ! if (port_target[i].pq[j].suffix_token == NULL) ! continue; ! ! if (!strcmp (p, port_target[i].pq[j].suffix_token)) ! break; ! } ! ! if (j < NUM_PORT_TARGETS) ! port_info[i].pq[j].complete = type; ! } else { ! /* A qualifier is not present, so set the type for all qualifiers. */ ! /* TODO: If the bare prefix appears after the prefix has appeared ! * with qualifiers in the line, then this will reset all qualifiers. ! * This is a bug. The solution is to be careful with @portability. */ ! for (j = 0; j < MAX_PORT_QUALIFIERS; j++) { ! port_info[i].pq[j].complete = type; ! } ! } ! } else { error ("unrecognised portability target `%s' ignored.\n", target); + } target = x; while (isspace (*target)) target++; *************** Node::read_portability(char *str) *** 233,263 **** void Node::write_portability() ! { char buffer[1024] = { 0 }; int note_number = 1; ! for (int i = 0; i < NUM_PORT_TARGETS; i++) ! { ! switch (port_info[i]) { ! case PORT_NO: ! strcat (buffer, "not "); ! strcat (buffer, port_target_string[i]); ! break; ! case PORT_YES: ! strcat (buffer, port_target_string[i]); ! break; ! case PORT_PARTIAL: ! strcat (buffer, "partially "); ! strcat (buffer, port_target_string[i]); ! break; } ! if (port_info[i] != PORT_UNKNOWN) ! { ! for (PortNote *p = port_notes; p; p = p->next) { ! if (p->target == i) { char smallbuffer[20]; p->number = note_number++; --- 348,459 ---- void Node::write_portability() ! { ! /* Column-width calculation variables */ ! size_t maxsize = 0; ! ssize_t size = 0; ! static int largest_target = -1; ! static char rightpad[80] = { 0 }; ! char buffer[1024] = { 0 }; + int qualifier_number = 0; + PortNote *p = NULL; int note_number = 1; ! /* If all qualifiers are set to a particular value, store it here ! * (one of PORT_*). Otherwise it should be set to -1. */ ! int all_port_qualifiers = -1; ! ! int i, j; ! ! /* Deduce the largest target name length, for table's left-hand column. */ ! if (largest_target == -1) ! { ! for (i = 0; i < NUM_PORT_TARGETS; i++) { ! if (strlen(port_target[i].prefix_name) > maxsize) ! { ! maxsize = strlen(port_target[i].prefix_name); ! largest_target = i; ! } } ! } ! ! /* Make the right-hand column 80 columns less the left-hand column width, ! * less some more for safety. */ ! if (rightpad[0] == '\0') { ! size = sizeof(rightpad) - maxsize - 10; ! if (size > 0) memset(rightpad, (int) 'x', size); ! } ! ! strcat (buffer, "@multitable {"); ! strcat (buffer, port_target[largest_target].prefix_name); ! strcat (buffer, "} {"); ! strcat (buffer, rightpad); ! strcat (buffer, "}\n"); ! ! for (i = 0; i < NUM_PORT_TARGETS; i++) ! { ! /* No information given => unknown => skip it. */ ! if (port_info[i].prefix_name == NULL) ! continue; ! ! /* Are all qualifiers set to the same value of one of PORT_*? */ ! for (j = 0; j < MAX_PORT_QUALIFIERS; j++) { ! /* Skip unnamed suffixes */ ! if (port_info[i].pq[j].suffix_name == NULL) ! continue; ! ! if (all_port_qualifiers == -1) { ! all_port_qualifiers = port_info[i].pq[j].complete; ! } else { ! if (all_port_qualifiers != port_info[i].pq[j].complete) { ! /* Not all port qualifiers have the same completion status. */ ! all_port_qualifiers = -1; ! break; ! } ! } ! } ! ! /* If all qualifiers are all set to unknown, skip this target. */ ! if (all_port_qualifiers == PORT_UNKNOWN) ! continue; ! ! /* Add an entry to the table. */ ! strcat (buffer, "@item "); ! strcat (buffer, port_target[i].prefix_name); ! strcat (buffer, " @tab "); ! ! qualifier_number = 0; ! ! /* Add positive or partial qualifiers to the list. */ ! for (j = 0; j < MAX_PORT_QUALIFIERS; j++) { ! /* Skip unnamed suffixes */ ! if (port_info[i].pq[j].suffix_name == NULL) ! continue; ! ! if ( (port_info[i].pq[j].complete != PORT_YES) ! && (port_info[i].pq[j].complete != PORT_PARTIAL)) ! continue; ! ! /* Add separator, if this isn't the first entry. */ ! qualifier_number++; ! if (qualifier_number > 1) ! strcat (buffer, "; "); ! ! if (port_info[i].pq[j].complete == PORT_YES) { ! strcat (buffer, port_info[i].pq[j].suffix_name); ! } else if (port_info[i].pq[j].complete == PORT_PARTIAL) { ! strcat (buffer, port_info[i].pq[j].suffix_name); ! strcat (buffer, " (partial)"); ! } ! ! /* Attach any qualifier-specific portability notes. */ ! for (p = port_notes; p; p = p->next) { ! if ( !strcmp (p->pi->prefix_token, port_info[i].prefix_token) ! && (p->pq != NULL) ! && !strcmp (p->pq->suffix_token, port_info[i].pq[j].suffix_token)) { char smallbuffer[20]; p->number = note_number++; *************** Node::write_portability() *** 266,284 **** break; } } - strcat (buffer, ", "); } - } ! { ! char *ch = strchr (buffer, 0) - 2; ! if (*ch == ',') ! *ch = 0; ! else ! strcpy (buffer, "Unknown."); } ! strcat (buffer, "\n\n"); add(buffer); if (note_number > 1) --- 462,528 ---- break; } } } ! /* Add negative qualifiers to the list. */ ! if (all_port_qualifiers == PORT_NO) ! strcat (buffer, "No"); ! ! for (j = 0; j < MAX_PORT_QUALIFIERS; j++) { ! /* Skip unnamed suffixes */ ! if (port_info[i].pq[j].suffix_name == NULL) ! continue; ! ! if (port_info[i].pq[j].complete != PORT_NO) ! continue; ! ! /* If all port qualifiers == PORT_NO, then we've already output. */ ! if (all_port_qualifiers != PORT_NO) { ! /* Add separator, if this isn't the first entry. */ ! qualifier_number++; ! if (qualifier_number > 1) ! strcat (buffer, "; "); ! ! strcat (buffer, "not "); ! strcat (buffer, port_info[i].pq[j].suffix_name); ! } ! ! /* Attach any qualifier-specific portability notes. */ ! for (p = port_notes; p; p = p->next) ! { ! if ( !strcmp (p->pi->prefix_token, port_info[i].prefix_token) ! && (p->pq != NULL) ! && !strcmp (p->pq->suffix_token, port_info[i].pq[j].suffix_token)) ! { ! char smallbuffer[20]; ! p->number = note_number++; ! sprintf (smallbuffer, " (see note %d)", p->number); ! strcat (buffer, smallbuffer); ! break; ! } ! } ! } ! ! /* Attach any target-specific portability notes. */ ! for (p = port_notes; p; p = p->next) ! { ! if ( (port_info[i].prefix_token != NULL) ! && !strcmp (p->pi->prefix_token, port_info[i].prefix_token) ! && (p->pq == NULL)) ! { ! char smallbuffer[20]; ! p->number = note_number++; ! sprintf (smallbuffer, " (see note %d)", p->number); ! strcat (buffer, smallbuffer); ! break; ! } ! } ! ! strcat (buffer, "\n"); } ! strcat (buffer, "@end multitable\n\n"); ! add(buffer); if (note_number > 1) *************** Node::write_portability() *** 288,294 **** add("\n"); add("@enumerate\n"); ! for (int i = 1; i < note_number; i++) { add("@item\n"); for (PortNote *p = port_notes; p; p = p->next) --- 532,538 ---- add("\n"); add("@enumerate\n"); ! for (i = 1; i < note_number; i++) { add("@item\n"); for (PortNote *p = port_notes; p; p = p->next) *************** void scan_directory(char *which) *** 495,501 **** Node *curnode; DIR *d = opendir(which); struct dirent *de; ! while (de = readdir(d)) { if (de->d_name[0] == '.') continue; --- 739,745 ---- Node *curnode; DIR *d = opendir(which); struct dirent *de; ! while ((de = readdir(d)) != NULL) { if (de->d_name[0] == '.') continue; *************** void scan_directory(char *which) *** 560,572 **** } } } //----------------------------------------------------------------------------- ! main(int argc, char **argv) { ! if (argc < 3) ! { ! fprintf(stderr, "Usage: mkdoc \n"); return 1; } --- 804,881 ---- } } } + //----------------------------------------------------------------------------- ! void list_portability (void) { ! int i, j; ! char buffer[40]; ! ! printf("Built-in portability targets:\n"); ! ! for (i = 0; i < NUM_PORT_TARGETS; i++) { ! if (port_target[i].pq[0].suffix_token == NULL) { ! printf("%-32s = %-32s\n", ! port_target[i].prefix_token, ! port_target[i].prefix_name); ! } else { ! for (j = 0; j < MAX_PORT_QUALIFIERS; j++) { ! if (port_target[i].pq[j].suffix_token == NULL) break; ! ! strcpy(buffer, port_target[i].prefix_token); ! strcat(buffer, "-"); ! strcat(buffer, port_target[i].pq[j].suffix_token); ! ! printf("%-32s = ", buffer); ! ! strcpy(buffer, port_target[i].prefix_name); ! strcat(buffer, ": "); ! strcat(buffer, port_target[i].pq[j].suffix_name); ! ! printf("%-32s\n", buffer); ! } ! } ! } ! } ! ! //----------------------------------------------------------------------------- ! ! void usage (void) ! { ! fprintf(stderr, ! "Usage: mkdoc [] \n" ! "\n" ! "Switches:\n" ! " -h, -?, --help - Display this help\n" ! " -l, --list-targets - List built-in portability targets\n" ! "\n"); ! } ! ! //----------------------------------------------------------------------------- ! ! int main (int argc, char **argv) ! { ! int i; ! ! // Scan for help options ! for (i = 1; i < argc; i++) { ! if ( !strcmp (argv[i], "-h") ! || !strcmp (argv[i], "--help") ! || !strcmp (argv[i], "-?") ) { ! usage(); ! return 1; ! } ! ! if ( !strcmp (argv[i], "-l") ! || !strcmp (argv[i], "--list-targets") ) { ! list_portability(); ! return 1; ! } ! } ! ! if (argc < 3) { ! usage(); return 1; }