view helpgen/helpgen.c @ 15:f5acaf0c8a29

Don't cast through "volatile int". Causes a gcc warning nowadays. XXX: should put something else back here to frighten the optimizer
author David A. Holland
date Tue, 31 May 2022 01:00:55 -0400
parents 13d2b8934445
children
line wrap: on
line source

#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "utils.h"
#include "topic.h"
#include "helpgen.h"


#define MAXTOPICS 512
#define MAXTOTTITLES (MAXTOPICS*4)

static struct topic *topics[MAXTOPICS];
static int ntopics;

void help_addtopic(struct topic *t) {
  if (ntopics >= MAXTOPICS) {
    fprintf(stderr, "Too many help topics (increase MAXTOPICS)\n");
    exit(1);
  }
  topics[ntopics++] = t;
}

////////////////////////////////////////////////////////////

static int titlesort(const void *av, const void *bv) {
  const char *a = *(const char *const *)av;
  const char *b = *(const char *const *)bv;
  return strcasecmp(a, b);
}

static int titlefind(const void *av, const void *bv) {
  const char *a = (const char *)av;
  const char *b = *(const char *const *)bv;
  return strcasecmp(a, b);
}

static void checkxrefs(void) {
  // check for dangling xrefs and duplicate titles

  const char *alltitles[MAXTOTTITLES];
  int ntitles = 0;

  int i, j, n;
  int bad = 0;

  for (i=0; i<ntopics; i++) {
    n = topic_getnumtitles(topics[i]);
    for (j=0; j<n; j++) {
      if (ntitles >= MAXTOTTITLES) {
	fprintf(stderr, "MAXTOTTITLES too small\n");
	exit(1);
      }
      alltitles[ntitles++] = topic_gettitle(topics[i], j);
    }
  }

  qsort(alltitles, ntitles, sizeof(alltitles[0]), titlesort);

  // check for dups
  for (i=1; i<ntitles; i++) {
    if (!strcasecmp(alltitles[i], alltitles[i-1])) {
      fprintf(stderr, "Duplicate title %s\n", alltitles[i]);
      bad = 1;
    }
  }

  // check refs
  for (i=0; i<ntopics; i++) {
    n = topic_getnumrefs(topics[i]);
    for (j=0; j<n; j++) {
      const char *ref;
      const void *result;

      ref = topic_getref(topics[i], j);
      result = bsearch(ref, alltitles, ntitles, sizeof(alltitles[0]),
		       titlefind);
      if (!result) {
	char *ref2;
	size_t reflen;

	reflen = strlen(ref);
	ref2 = dostrdup(ref);
	if (reflen > 0 && ref2[reflen-1]=='s') {
	  ref2[reflen-1] = 0;
	  result = bsearch(ref2, alltitles, ntitles, sizeof(alltitles[0]),
			   titlefind);
	}
	free(ref2);
      }

      if (!result) {
	fprintf(stderr, "Dangling crossreference %s from %s\n", ref,
		topic_gettitle(topics[i], 0));
	bad = 1;
      }
    }
  }

  if (bad) {
    exit(1);
  }
}

////////////////////////////////////////////////////////////

static void usage(const char *av0) {
  fprintf(stderr, "usage: %s [-t type] infile outfile\n", av0);
  fprintf(stderr, "   type may be: c html\n");
  exit(1);
}

int main(int argc, char *argv[]) {
  void (*outfunc)(const char *, struct topic **, int);
  const char *outputtype = "c";
  int ch;

  while ((ch = getopt(argc, argv, "t:"))!=-1) {
    switch (ch) {
      case 't': outputtype = optarg; break;
      default: usage(argv[0]); break;
    }
  }
  if (optind != argc-2) {
    usage(argv[0]);
  }

  const char *infile = argv[optind++];
  const char *outfile = argv[optind++];

  if (!strcmp(outputtype, "c")) {
    outfunc = cout;
  }
  else if (!strcmp(outputtype, "html")) {
    outfunc = htmlout;
  }
  else {
    usage(argv[0]);
  }

  load(infile);
  checkxrefs();
  outfunc(outfile, topics, ntopics);

  return 0;
}