Mail Archives: djgpp-workers/2001/01/23/17:06:42
Hello.
This is a resend of a couple of mails. No-one commented last time, so I'm
posting it again. The originals were dated Thu, 23 Nov 2000. If the size
of the patch is a problem, I'm not sure what I can do to make it easier to
read, since it really is just one change.
I'd rather apply the updates to mkdoc one at a time, since I don't know
when I'll have time to work on the other requests changes.
Thanks, bye, Rich =]
---Things I forgot---
I forgot a couple of things:
Richard Dawe wrote:
> What the patch doesn't do:
>
> * You can't define your portability types "on the fly" as suggested by
> DJ.
* An option to dump out the table of targets and their qualifiers.
* Multi-line @port-note support.
---Original message---
Hello.
It's been a while, but here's another take on my patch to mkdoc.cc. Here's
what it does:
* Allows you to specify a portability target, e.g. ansi, and a qualifier,
e.g. c99, so you can have portability statements like:
@portability ansi-c99
or:
@portability unix-98
It handles the case where you just specify 'ansi' by listing all the ANSI
standards it knows about - C89, C99. The targets + qualifiers are table
driven, so you can add commonly-used portability cases easily.
* Puts the portability information in a tabular format.
Changes since the last patch:
* Now puts all !portability cases at the end of a line, to avoid a
confusing mix of postives and negatives. Previously we could have:
@portability !ansi, posix
producing:
Not ANSI, POSIX
It is unclear from this whether it's only "not ANSI" or neither ANSI nor
POSIX that are supported. Moving to a tabular format removed this vagarity
initially, e.g.
ANSI: No
POSIX: Yes
But then adding C99 brought the confusion back. Now we can have:
@portability ansi-c89, !ansi-c99
producing:
ANSI/ISO C C89, not C99
or:
@portability !ansi-c89, ansi-c99
producing:
ANSI/ISO C C99, not C89
What the patch doesn't do:
* You can't define your portability types "on the fly" as suggested by DJ.
I also have a Perl script that converts @portability lines with 'ansi' to
equivalent lines with both 'ansi-c89', 'ansi-c99', if anyone's interested.
The script isn't much use now, since the patched mkdoc handles it as you'd
expect (!ansi -> !ansi-c89, !ansi-c99, ansi -> ansi-c89, ansi-c99).
Comments, etc. welcome. Bye, Rich =]
*** mkdoc.cc.orig Thu Nov 23 17:21:42 2000
--- mkdoc.cc Thu Nov 23 17:21:50 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 */
*************** 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;
--- 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_YES }
! }
! },
! /* POSIX */
! { "posix", "POSIX",
! {
! { "1003.2-1992", "1003.2-1992",
! PORT_TARGET_POSIX_1003_2_1992, PORT_YES },
! { 0 }
! }
! },
! /* 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;
};
--- 106,113 ----
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);
--- 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);
*************** 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;
}
--- 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;
}
*************** 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;
--- 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;
*************** 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;
--- 211,252 ----
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 == '~')
{
--- 266,276 ----
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++;
--- 285,340 ----
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++;
--- 345,456 ----
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)
--- 459,525 ----
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)
--- 529,535 ----
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;
--- 736,742 ----
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 <directory> <output file>\n");
return 1;
}
--- 801,878 ----
}
}
}
+
//-----------------------------------------------------------------------------
! 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 [<switches>] <directory> <output file>\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;
}
- Raw text -