Sender: rich AT phekda DOT freeserve DOT co DOT uk Message-ID: <396792CB.85E1BCDE@phekda.freeserve.co.uk> Date: Sat, 08 Jul 2000 21:44:59 +0100 From: Richard Dawe X-Mailer: Mozilla 4.51 [en] (X11; I; Linux 2.2.14 i586) X-Accept-Language: de,fr MIME-Version: 1.0 To: DJGPP workers Subject: mkdoc patch, take 2 Content-Type: multipart/mixed; boundary="------------606FDF1B771A43BACB82D4B1" Reply-To: djgpp-workers AT delorie DOT com This is a multi-part message in MIME format. --------------606FDF1B771A43BACB82D4B1 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Hello. Please find attached revision two of my mkdoc patch. Attached are a diff for mkdoc.cc, wc204.txi and a new sample file, to show the new features off. The distinction between C89 and C99 is a special case of a more general problem, so I decided to rework the way the portability info is done, in a backwards-compatible way. Here's how the new system works. The whole thing is table-driven. Each portability target has several "qualifiers". So there's an ANSI ISO/C target "ansi", for which there are qualifiers "-c89", "-c99". Each target has a default status for each qualifier, so if you just use: @portability ansi it defaults to C89 portability. You could have: @portability ansi-c89, !ansi-c99 The portability notes can refer to a whole target, or to individual qualifiers, e.g: @port-note ansi-c89 Blah blah blah @port-note ansi-c99 Yadda yadda yadda We now have a "unix" target, which has the qualifier "98" for Unix98/SUSv2: @portability unix98 We might want to add 4.2BSD or 4.4BSD too, e.g. unix-4.2-bsd, unix-4.4-bsd. Here's an example of the output, from sample2.txh: Portability ----------- ANSI/ISO C not C89 (see note 1); not C99 POSIX 1003.2-1992 (see note 2) Unix Unix98 (partial) (see note 3) Notes: 1. You must be joking! 2. Perhaps this can be put into the combined POSIX & Unix98 combined standard? Hmm, maybe not. 3. Naah, only joking. Of course, the distinction between C89 and C99 means that what was previously one entry per row is now back to the multiple entries per row, which I caused me to suggest changing in mkdoc in the first place. Ah well. ;) I have a couple of questions: 1. When producing @multitable in texinfo, is there an easy way to make a column consume the rest of the table? The problem here is that we have a 2-column table. The left-hand column's width can be calculated easily, but the right column should use the remaining space. I have a hack based on an assumption of 80-columns width. 2. With the default qualifiers for the ansi target, C89 compatibility is set to yes, but C99 is set to unknown. Should the unknown part be displayed in the portability? I think this could be confusing for users. A couple of other improvements for mkdoc spring to mind: 1. Add an option to dump out the table of targets and their qualifiers. 2. Make @port-note be a multi-line @ command, e.g. @port-note ansi This uses four lines. @end port-note or: @port-note ansi {This uses one line.} Thanks, bye, Rich =] -- Richard Dawe [ mailto:richdawe AT bigfoot DOT com | http://www.bigfoot.com/~richdawe/ ] --------------606FDF1B771A43BACB82D4B1 Content-Type: text/plain; charset=us-ascii; name="mkdoc3-2.cc.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="mkdoc3-2.cc.diff" *** mkdoc.cc.orig Mon Jul 3 21:48:59 2000 --- mkdoc3.cc Sat Jul 8 18:11:32 2000 *************** *** 1,3 **** --- 1,4 ---- + /* 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 */ *************** *** 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; --- 30,94 ---- 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 ! /* 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_UNKNOWN } ! } ! }, ! /* POSIX */ ! { "posix", "POSIX", ! { ! { "-1003.2-1992", "1003.2-1992", ! PORT_TARGET_POSIX_1003_2_1992, PORT_YES }, ! { 0 } ! } ! }, ! /* SUS */ ! { "unix", "Unix", ! { ! { "98", "Unix98", PORT_TARGET_UNIX_98, PORT_UNKNOWN }, ! { 0 } ! } ! } ! }; struct Tree { TreeNode *nodes; *************** *** 59,65 **** struct PortNote { struct PortNote *next; ! int target; int number; char *note; }; --- 106,113 ---- struct PortNote { struct PortNote *next; ! PortInfo *pi; ! PortQualifier *pq; int number; char *note; }; *************** *** 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); --- 121,127 ---- Line *lastline; Tree subnodes; char *filename; ! PortInfo port_info[NUM_PORT_TARGETS]; PortNote *port_notes; PortNote *last_port_note; Node(char *name, char *cat); *************** *** 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; } --- 155,162 ---- 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; } *************** *** 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; --- 200,208 ---- 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; *************** *** 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; --- 211,245 ---- 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))) ! 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); + + for (j = 0; j < MAX_PORT_QUALIFIERS; j++) { + if (port_target[i].pq[j].suffix_token == NULL) continue; + if (!strcmp (x, port_target[i].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; *************** *** 196,203 **** Node::read_portability(char *str) { char *targets = dj_strlwr (strdup (str)); ! char *x, *target = targets; ! int type,i; while (isspace (*target)) target++; while (*target) { --- 259,266 ---- 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) { *************** *** 217,228 **** 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++; --- 280,310 ---- 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))) ! 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])); ! } ! ! 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 { error ("unrecognised portability target `%s' ignored.\n", target); + } target = x; while (isspace (*target)) target++; *************** *** 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++; --- 315,409 ---- 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; + 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++) + { + strcat (buffer, "@item "); + strcat (buffer, port_target[i].prefix_name); + strcat (buffer, " @tab "); + + for (qualifier_number = j = 0; j < MAX_PORT_QUALIFIERS; j++) { + /* No information given => unknown. */ + if (port_info[i].prefix_name == NULL) { + strcat (buffer, "Unknown"); + break; + } + + if (port_info[i].pq[j].suffix_name == NULL) continue; + + switch (port_info[i].pq[j].complete) + { case PORT_NO: + case PORT_YES: + case PORT_PARTIAL: + qualifier_number++; + if (qualifier_number > 1) strcat (buffer, "; "); + break; + default: + break; + } + + switch (port_info[i].pq[j].complete) + { + case PORT_NO: strcat (buffer, "not "); ! strcat (buffer, port_info[i].pq[j].suffix_name); break; case PORT_YES: ! strcat (buffer, port_info[i].pq[j].suffix_name); break; case PORT_PARTIAL: ! strcat (buffer, port_info[i].pq[j].suffix_name); ! strcat (buffer, " (partial)"); break; ! default: ! break; ! } ! ! /* 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++; *************** *** 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) --- 412,439 ---- 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) *************** *** 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) --- 443,449 ---- add("\n"); add("@enumerate\n"); ! for (i = 1; i < note_number; i++) { add("@item\n"); for (PortNote *p = port_notes; p; p = p->next) *************** *** 495,501 **** Node *curnode; DIR *d = opendir(which); struct dirent *de; ! while (de = readdir(d)) { if (de->d_name[0] == '.') continue; --- 650,656 ---- Node *curnode; DIR *d = opendir(which); struct dirent *de; ! while ((de = readdir(d)) != NULL) { if (de->d_name[0] == '.') continue; --------------606FDF1B771A43BACB82D4B1 Content-Type: text/plain; charset=us-ascii; name="wc204.txi.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="wc204.txi.diff" *** wc204.txi.orig Mon Jul 3 21:52:28 2000 --- wc204.txi Mon Jul 3 21:57:21 2000 *************** *** 54,56 **** --- 54,59 ---- @findex fsdb AT r{, check for EXE extension} @code{fsdb} checks for executables and loads them even if the extension @file{.exe} isn't given in the command line. + + The portability information in the library documentation is now presented in + tabular form, for easier interpretation. --------------606FDF1B771A43BACB82D4B1 Content-Type: text/plain; charset=us-ascii; name="sample2.txh" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="sample2.txh" @c ---------------------------------------------------------------------- @node gesticulate, officelib @subheading Syntax @example #include int gesticulate(int wildly); @end example @subheading Description When you call @code{gesticulate}, an Office Assistant appears, in order to help you debug your OfficeScript scripts by using indicative gestures while whispering soothing words of advice. If it's particularly late at night, it may be useful to use the @var{wildly} parameter to make its intent more obvious. Alternatively, a black coffee or Jolt Cola may increase your awareness, so as to make the @var{wildly} option unnecessary. @subheading Return Value This function returns zero on success or non-zero if it fails. The error is stored in @var{oerrno} - possible errors are: @table @samp @item EAGAIN It's too late - the Office Assistant is asleep. @item EBUSY The Office Assistant isn't back from the pub yet. @item ECHILD You're too young to be debugging at this time of night! @item ENODEV The Office Assistant has no arms to gesticulate with. @item ENOENT The Office Assistant discovered that no bugs exist in your code. You're being paranoid! @end table @subheading Portability @port-note ansi-c89 You must be joking! @port-note posix Perhaps this can be put into the combined POSIX & Unix98 combined standard? Hmm, maybe not. @port-note unix98 Naah, only joking. @portability !ansi-c89, !ansi-c99, !posix, ~unix98 @subheading Example @example if (gesticulate() == -1) @{ oerror("crashnburn"); GPF(); @} @end example --------------606FDF1B771A43BACB82D4B1--