/************************************************* * The PMW Music Typesetter - 3rd incarnation * *************************************************/ /* Copyright (c) Philip Hazel, 1991 - 2020 */ /* Written by Philip Hazel, starting November 1991 */ /* This file last modified: December 2020 */ /* This file contains initializing and other housekeeping functions. */ #include "rdargs.h" #include "pmwhdr.h" #include "outhdr.h" /* NO_PMWRC is set when --disable-pmwrc is given to "configure". */ #ifndef NO_PMWRC #include #include #endif /************************************************* * Read a MIDI translation file * *************************************************/ /* These files are short: reading them twice in order to get the correct size doesn't take much time and saves much hassle. The files contain translation between names and MIDI voice numbers or names and MIDI "pitches" for untuned percussion. Arguments: anchor where to build filename the file name Returns: nothing; if the file fails to open, no action is taken */ void read_midi_translation(uschar **anchor, uschar *filename) { FILE *f = Ufopen(filename, "r"); int length = 0; uschar *p; uschar line[60]; if (f == NULL) return; while (Ufgets(line, 60, f) != NULL) { line[Ustrlen(line)-1] = 0; if (!isdigit(line[0])) continue; /* Ignore line not starting with a digit */ length += Ustrlen(line+4) + 2; } if (length == 0) return; /* No usable text in the file */ /* We store the file in one long byte string. Each name is followed by a zero byte and then a binary byte containing its number. */ *anchor = malloc(length+1); p = *anchor; rewind(f); while (Ufgets(line, 60, f) != NULL) { line[Ustrlen(line)-1] = 0; if (!isdigit(line[0])) continue; Ustrcpy(p, line+4); p += Ustrlen(p) + 1; *p++ = Uatoi(line); } /* An empty name marks the end of the list */ *p = 0; fclose(f); } /************************************************* * Local initialization * *************************************************/ /* This is called before argument decoding is done. It is passed the argument list, and it has the opportunity of modifying that list as it copies it into a new vector. Unless configured not to include this code, we search for a .pmwrc file and stuff it on the front of the arguments. Arguments: argc argc from main() argv argv from main() nargv where to return the possibly modified argv arg_pattern the argument decoding pattern, to check for validity Returns: new argc value */ int init_command(int argc, char **argv, char **nargv, const char *arg_pattern) { int ap = 0; int nargc = 0; (void)argc; /* Unused; avoid compiler warning */ nargv[nargc++] = argv[ap++]; /* Program name */ if (argv[1] != NULL && strcmp(argv[1], "-norc") == 0) { (void)arg_pattern; ap++; /* Just skip over -norc if it's first; don't read the file */ } /* Processing ~/.pmwrc needs to be cut out on non-Unix-like systems. If -norc is given, it doesn't matter because that's what is happening by default. */ #ifndef NO_PMWRC else { struct passwd *pw = getpwuid(geteuid()); if (pw != NULL) { uschar buff[256]; struct stat statbuf; Ustrcpy(buff, pw->pw_dir); Ustrcat(buff, "/.pmwrc"); if (stat(CS buff, &statbuf) == 0) { arg_result results[64]; FILE *f = Ufopen(buff, "r"); /* Failure to open a file that statted OK is a hard error */ if (f == NULL) error_moan(ERR41, buff, strerror(errno)); /* Add items from the file */ while (fgets(CS buff, sizeof(buff), f) != NULL) { uschar *p = buff; while (isspace(*p)) p++; while (*p != 0) { uschar *pp = p; while (*p != 0 && !isspace(*p)) p++; nargv[nargc] = malloc(p - pp + 1); Ustrncpy(nargv[nargc], pp, p - pp); nargv[nargc++][p-pp] = 0; while (isspace(*p)) p++; } } fclose(f); /* Check that what we have obtained from the .pmwrc file is a complete set of options; we don't want to end up with one that expects a data value, because that would subvert the argument on the real command line, possibly doing damage. */ if (rdargs(nargc, nargv, arg_pattern, results) != 0) error_moan(ERR124, results[0].text, results[1].text); /* Hard */ } /* stat() problem other than file not found is serious */ else if (errno != ENOENT) error_moan(ERR41, buff, strerror(errno)); /* Hard */ } } #endif /* NO_PMWRC */ /* Copy the remaining stuff from the original command line */ while (argv[ap] != NULL) nargv[nargc++] = argv[ap++]; nargv[nargc] = NULL; return nargc; } /************************************************* * Relativize a file name * *************************************************/ /* The name must be in a buffer that is long enough to take the additional path if necessary, because it is modified in place. If the name does not start with '/', we make it relative to the main input file name. Argument: name the name under consideration len the total buffer length Returns: nothing */ void sys_relativize(uschar *name, int len) { int im, in; DEBUG(("sys_relativize(%s) entered\n", name)); if (name[0] == '/' || main_filename == NULL) return; im = Ustrlen(main_filename); while (im > 0 && main_filename[--im] != '/') {} if (im != 0) im++; in = Ustrlen(name); if (im + in + 1 > len) error_moan(ERR136, "Fully qualified file name", len); /* Hard */ memmove(name + im, name, in + 1); memcpy(name, main_filename, im); DEBUG(("relativized to %s\n", name)); } /* End of init.c */