26 #include <osiFileName.h> 27 #include <osiUnistd.h> 29 #define MAX_BUFFER_SIZE 4096 35 #define ENTER fprintf(stderr, "%*sEntering %s\n", 2*din++, "", __FUNCTION__) 37 #define STEP(s) fprintf(stderr, "%*s%s: %s\n", 2*din, "", __FUNCTION__, s) 38 #define STEPS(s, v) fprintf(stderr, "%*s%s: %s '%s'\n", 2*din, "", __FUNCTION__, s, v) 39 #define STEPD(s, v) fprintf(stderr, "%*s%s: %s %d\n", 2*din, "", __FUNCTION__, s, v) 41 #define EXIT fprintf(stderr, "%*s%s: Returning\n", 2*din--, "", __FUNCTION__) 42 #define EXITD(r) fprintf(stderr, "%*s%s: Returning %d\n", 2*din--, "", __FUNCTION__, r) 43 #define EXITS(r) fprintf(stderr, "%*s%s: Returning '%s'\n", 2*din--, "", __FUNCTION__, r) 60 static void inputConstruct(
inputData **ppvt);
61 static void inputDestruct(
inputData *
const pvt);
62 static void inputAddPath(
inputData *
const pvt,
const char *
const pval);
63 static void inputBegin(
inputData *
const pvt,
const char *
const fileName);
64 static char *inputNextLine(
inputData *
const pvt);
65 static void inputNewIncludeFile(
inputData *
const pvt,
const char *
const name);
66 static void inputErrPrint(
const inputData *
const pvt);
71 static void substituteOpen(
subInfo **ppvt,
const std::string& substitutionName);
72 static void substituteDestruct(
subInfo *
const pvt);
74 static bool substituteGetGlobalSet(
subInfo *
const pvt);
75 static const char *substituteGetReplacements(
subInfo *
const pvt);
76 static const char *substituteGetGlobalReplacements(
subInfo *
const pvt);
79 static void usageExit(
const int status);
80 static void abortExit(
const int status);
81 static void addMacroReplacements(
MAC_HANDLE *
const macPvt,
82 const char *
const pval);
83 static void makeSubstitutions(
inputData *
const inputPvt,
85 const char *
const templateName);
89 static bool opt_D =
false;
91 static char *outFile = 0;
92 static int numDeps = 0, depHashes[
MAX_DEPS];
95 int main(
int argc,
char **argv)
100 std::string substitutionName;
101 char *templateName = 0;
102 bool localScope =
true;
104 inputConstruct(&inputPvt);
106 while ((argc > 1) && (argv[1][0] ==
'-')) {
107 int narg = (strlen(argv[1]) == 2) ? 2 : 1;
108 pval = (narg == 1) ? (argv[1] + 2) : argv[2];
110 if (strncmp(argv[1],
"-I", 2) == 0) {
111 inputAddPath(inputPvt, pval);
113 else if (strcmp(argv[1],
"-D") == 0) {
117 else if(strncmp(argv[1],
"-o", 2) == 0) {
120 else if(strncmp(argv[1],
"-M", 2) == 0) {
121 addMacroReplacements(macPvt, pval);
123 else if(strncmp(argv[1],
"-S", 2) == 0) {
124 substitutionName = pval;
126 else if (strcmp(argv[1],
"-V") == 0) {
130 else if (strcmp(argv[1],
"-g") == 0) {
134 else if (strcmp(argv[1],
"-h") == 0) {
138 fprintf(
stderr,
"msi: Bad argument \"%s\"\n", argv[1]);
143 for (
int i = 1;
i < argc;
i++)
144 argv[
i] = argv[
i + narg];
151 fprintf(
stderr,
"msi: Too many arguments\n");
157 fprintf(
stderr,
"msi: Option -D requires -o for Makefile target\n");
162 else if (outFile && freopen(outFile,
"w",
stdout) ==
NULL) {
163 fprintf(
stderr,
"msi: Can't open %s for writing: %s\n",
164 outFile, strerror(errno));
171 if (substitutionName.empty()) {
172 STEP(
"Single template+substitutions file");
173 makeSubstitutions(inputPvt, macPvt, templateName);
180 STEPS(
"Substitutions from file", substitutionName.c_str());
181 substituteOpen(&substitutePvt, substitutionName);
183 isGlobal = substituteGetGlobalSet(substitutePvt);
185 STEP(
"Handling global macros");
186 const char *macStr = substituteGetGlobalReplacements(substitutePvt);
188 addMacroReplacements(macPvt, macStr);
190 else if ((isFile = substituteGetNextSet(substitutePvt, &filename))) {
192 filename = templateName;
194 fprintf(
stderr,
"msi: No template file\n");
198 STEPS(
"Handling template file", filename);
200 while ((macStr = substituteGetReplacements(substitutePvt))) {
204 addMacroReplacements(macPvt, macStr);
205 makeSubstitutions(inputPvt, macPvt, filename);
211 }
while (isGlobal || isFile);
212 substituteDestruct(substitutePvt);
216 inputDestruct(inputPvt);
225 void usageExit(
const int status)
228 "Usage: msi [options] [template]\n" 229 " stdin is used if neither template nor substitution file is given\n" 231 " -h Print this help message\n" 232 " -D Output file dependencies, not substitutions\n" 233 " -V Undefined macros generate an error\n" 234 " -g All macros have global scope\n" 235 " -o<FILE> Send output to <FILE>\n" 236 " -I<DIR> Add <DIR> to include file search path\n" 237 " -M<SUBST> Add <SUBST> to (global) macro definitions\n" 238 " (<SUBST> takes the form VAR=VALUE,...)\n" 239 " -S<FILE> Expand the substitutions in FILE\n");
243 void abortExit(
const int status)
252 static void addMacroReplacements(
MAC_HANDLE *
const macPvt,
253 const char *
const pval)
260 fprintf(
stderr,
"msi: Error from macParseDefns\n");
266 fprintf(
stderr,
"Error from macInstallMacros\n");
274 static const char *cmdNames[] = {
"include",
"substitute"};
276 static void makeSubstitutions(
inputData *
const inputPvt,
278 const char *
const templateName)
285 inputBegin(inputPvt, templateName);
286 while ((input = inputNextLine(inputPvt))) {
293 while (*p && (isspace((
int) *p))) ++p;
296 if (*p && (*p==
'i' || *p==
's'))
305 for (i = 0; i <
NELEMENTS(cmdNames); i++) {
306 if (strstr(command, cmdNames[i])) {
310 if (cmdind < 0)
goto endcmd;
311 p = command + strlen(cmdNames[cmdind]);
313 while (*p && (isspace((
int) *p))) ++p;
315 if ((*p == 0) || (*p !=
'"'))
goto endcmd;
318 while (*p && (*p !=
'"')) {
320 if ((p[0] ==
'\\') && p[1] ==
'"') {
325 if (*p ==
'"')
break;
330 if (*p == 0)
goto endcmd;
332 while (*++p ==
' ') ;
333 if (*p !=
'\n' && *p != 0)
goto endcmd;
334 std::string
copy = std::string(pstart, pend);
338 inputNewIncludeFile(inputPvt, copy.c_str());
342 addMacroReplacements(macPvt, copy.c_str());
346 fprintf(
stderr,
"msi: Logic error in makeSubstitutions\n");
347 inputErrPrint(inputPvt);
354 if (expand && !opt_D) {
355 STEP(
"Expanding to output stream");
358 if (opt_V == 1 && n < 0) {
359 fprintf(
stderr,
"msi: Error - undefined macros present\n");
377 inputData() { memset(inputBuffer, 0,
sizeof(inputBuffer) *
sizeof(inputBuffer[0])); };
381 static void inputCloseFile(
inputData *pinputData);
382 static void inputCloseAllFiles(
inputData *pinputData);
384 static void inputConstruct(
inputData **ppvt)
389 static void inputDestruct(
inputData *
const pinputData)
391 inputCloseAllFiles(pinputData);
395 static void inputAddPath(
inputData *
const pinputData,
const char *
const path)
405 while (pdir && *pdir) {
406 bool emptyName = (*pdir == sep);
407 if (emptyName) ++pdir;
409 std::string directory;
411 pcolon = strchr(pdir, sep);
412 len = (pcolon ? (pcolon - pdir) : strlen(pdir));
414 directory = std::string(pdir, len);
417 if (pdir && *(pdir + 1) != 0) ++pdir;
428 pinputData->
pathList.push_back(directory);
433 static void inputBegin(
inputData *
const pinputData,
const char *
const fileName)
436 inputCloseAllFiles(pinputData);
437 inputOpenFile(pinputData, fileName);
441 static char *inputNextLine(
inputData *
const pinputData)
443 std::list<inputFile>& inFileList = pinputData->
inputFileList;
446 while (!inFileList.empty()) {
454 inputCloseFile(pinputData);
460 static void inputNewIncludeFile(
inputData *
const pinputData,
461 const char *
const name)
464 inputOpenFile(pinputData,name);
468 static void inputErrPrint(
const inputData *
const pinputData)
472 const std::list<inputFile>& inFileList = pinputData->
inputFileList;
473 std::list<inputFile>::const_iterator inFileIt = inFileList.begin();
474 while (inFileIt != inFileList.end()) {
475 fprintf(
stderr,
"line %d of ", inFileIt->lineNum);
477 if (!inFileIt->filename.empty()) {
478 fprintf(
stderr,
" file %s\n", inFileIt->filename.c_str());
481 fprintf(
stderr,
"stdin:\n");
484 if (++inFileIt != inFileList.end()) {
485 fprintf(
stderr,
" included from ");
497 std::list<std::string>& pathList = pinputData->
pathList;
498 std::list<std::string>::iterator pathIt = pathList.end();
499 std::string fullname;
507 else if (pathList.empty() || strchr(filename,
'/')){
508 STEPS(
"Opening ", filename);
509 fp = fopen(filename,
"r");
512 pathIt = pathList.begin();
513 while(pathIt != pathList.end()) {
514 fullname = *pathIt +
"/" +
filename;
515 STEPS(
"Trying", filename);
516 fp = fopen(fullname.c_str(),
"r");
524 fprintf(
stderr,
"msi: Can't open file '%s'\n", filename);
525 inputErrPrint(pinputData);
532 if (pathIt != pathList.end()) {
547 while (i < numDeps) {
548 if (hash == depHashes[i++]) {
554 const char *wrap = numDeps ?
" \\\n" :
"";
558 depHashes[numDeps++] = hash;
572 static void inputCloseFile(
inputData *pinputData)
574 std::list<inputFile>& inFileList = pinputData->
inputFileList;
576 if(!inFileList.empty()) {
578 if (fclose(inFile.
fp))
579 fprintf(
stderr,
"msi: Can't close input file '%s'\n", inFile.
filename.c_str());
580 inFileList.erase(inFileList.begin());
585 static void inputCloseAllFiles(
inputData *pinputData)
588 const std::list<inputFile>& inFileList = pinputData->
inputFileList;
589 while(!inFileList.empty()) {
590 inputCloseFile(pinputData);
621 static char *subGetNextLine(
subFile *psubFile);
623 static void subFileErrPrint(
subFile *psubFile,
const char * message);
624 static void freeSubFile(
subInfo *psubInfo);
625 static void freePattern(
subInfo *psubInfo);
626 static void catMacroReplacements(
subInfo *psubInfo,
const char *
value);
628 void freeSubFile(
subInfo *psubInfo)
634 if (fclose(psubFile->
fp))
635 fprintf(
stderr,
"msi: Can't close substitution file\n");
643 void freePattern(
subInfo *psubInfo)
651 static void substituteDestruct(
subInfo *
const psubInfo)
654 freeSubFile(psubInfo);
655 freePattern(psubInfo);
660 static void substituteOpen(
subInfo **ppvt,
const std::string& substitutionName)
672 fp = fopen(substitutionName.c_str(),
"r");
674 fprintf(
stderr,
"msi: Can't open file '%s'\n", substitutionName.c_str());
683 subGetNextToken(psubFile);
687 static bool substituteGetGlobalSet(
subInfo *
const psubInfo)
693 subGetNextToken(psubFile);
696 strcmp(psubFile->
string,
"global") == 0) {
697 subGetNextToken(psubFile);
706 static bool substituteGetNextSet(
subInfo *
const psubInfo,
char **
filename)
713 subGetNextToken(psubFile);
721 strcmp(psubFile->
string,
"file") == 0) {
724 STEP(
"Parsed 'file'");
727 subFileErrPrint(psubFile,
"Parse error, expecting a filename");
731 freePattern(psubInfo);
734 len = strlen(psubFile->
string);
735 if (psubFile->
string[0] ==
'"' &&
736 psubFile->
string[len - 1] ==
'"') {
737 psubFile->
string[len - 1] =
'\0';
747 subFileErrPrint(psubFile,
"Parse error, expecting '{'");
751 subGetNextToken(psubFile);
756 subGetNextToken(psubFile);
764 subFileErrPrint(psubFile,
"Parse error, unexpected '}'");
769 strcmp(psubFile->
string,
"pattern") != 0) {
770 subFileErrPrint(psubFile,
"Parse error, expecting 'pattern'");
774 STEP(
"Parsed 'pattern'");
775 freePattern(psubInfo);
781 subFileErrPrint(psubFile,
"Parse error, expecting '{'");
796 subFileErrPrint(psubFile,
"Parse error, expecting '}'");
800 subGetNextToken(psubFile);
805 static const char *substituteGetGlobalReplacements(
subInfo *
const psubInfo)
813 subGetNextToken(psubFile);
819 freePattern(psubInfo);
820 subGetNextToken(psubFile);
835 switch(subGetNextToken(psubFile)) {
837 subGetNextToken(psubFile);
842 catMacroReplacements(psubInfo,
",");
846 catMacroReplacements(psubInfo, psubFile->
string);
850 subFileErrPrint(psubFile,
"Parse error, unexpected '{'");
853 subFileErrPrint(psubFile,
"Parse error, incomplete file?");
859 static const char *substituteGetReplacements(
subInfo *
const psubInfo)
867 subGetNextToken(psubFile);
873 freePattern(psubInfo);
874 subGetNextToken(psubFile);
890 bool gotFirstPattern =
false;
893 std::list<std::string>& patternList = psubInfo->
patternList;
894 std::list<std::string>::iterator patternIt = patternList.begin();
897 subGetNextToken(psubFile);
903 subFileErrPrint(psubFile,
"Parse error, expecting macro value");
908 catMacroReplacements(psubInfo,
",");
909 gotFirstPattern =
true;
911 if (patternIt != patternList.end()) {
912 catMacroReplacements(psubInfo, patternIt->c_str());
913 catMacroReplacements(psubInfo,
"=");
914 catMacroReplacements(psubInfo, psubFile->
string);
918 subFileErrPrint(psubFile,
"Warning, too many values given");
925 switch(subGetNextToken(psubFile)) {
927 subGetNextToken(psubFile);
932 catMacroReplacements(psubInfo,
",");
936 catMacroReplacements(psubInfo, psubFile->
string);
940 subFileErrPrint(psubFile,
"Parse error, unexpected '{'");
943 subFileErrPrint(psubFile,
"Parse error, incomplete file?");
949 static char *subGetNextLine(
subFile *psubFile)
957 }
while (pline && psubFile->
inputBuffer[0] ==
'#');
972 static void subFileErrPrint(
subFile *psubFile,
const char * message)
974 fprintf(
stderr,
"msi: %s\n",message);
975 fprintf(
stderr,
" in substitution file '%s' at line %d:\n %s",
993 if (*p == 0 || *p ==
'\n' || *p ==
'#') {
994 STEP(
"Got newline/comment");
995 p = subGetNextLine(psubFile);
1000 while (isspace((
int) *p)) p++;
1013 if (*p == 0 || isspace((
int) *p) || *p ==
',') {
1014 STEP(
"Got space/comma");
1015 while (isspace((
int) *p) || *p ==
',') p++;
1023 pto = &psubFile->
string[0];
1026 if (*p == 0 || *p ==
'\n') {
1027 subFileErrPrint(psubFile,
"Strings must be on single line\n");
1031 if ((p[0] ==
'\\') && p[1] ==
'"') {
1046 pto = &psubFile->
string[0];
1048 while (!isspace((
int) *p) && (strspn(p,
"\",{}") == 0))
1058 return psubFile->
token;
1061 static void catMacroReplacements(
subInfo *psubInfo,
const char *
value)
1064 STEPS(
"Appending", value);
unsigned int epicsStrHash(const char *str, unsigned int seed)
std::list< std::string > patternList
LIBCOM_API long epicsStdCall macParseDefns(MAC_HANDLE *handle, const char *defns, char **pairs[])
Parse macro definitions into an array of {name, value} pairs.
char inputBuffer[MAX_BUFFER_SIZE]
#define OSI_PATH_LIST_SEPARATOR
std::string substitutionName
struct inputData inputData
Miscellaneous macro definitions.
void copy(PVValueArray< T > &pvFrom, size_t fromOffset, size_t fromStride, PVValueArray< T > &pvTo, size_t toOffset, size_t toStride, size_t count)
Copy a subarray from one scalar array to another.
long epicsStdCall macExpandString(MAC_HANDLE *handle, const char *src, char *dest, long capacity)
Expand a string which may contain macro references.
char *epicsStdCall macEnvExpand(const char *str)
Expand environment variables in a string.
struct inputFile inputFile
Macro substitution context, for use by macLib routines only.
void epicsStdCall macSuppressWarning(MAC_HANDLE *handle, int suppress)
Disable or enable warning messages.
char * epicsStrDup(const char *s)
long epicsStdCall macDeleteHandle(MAC_HANDLE *handle)
Marks a handle invalid, and frees all storage associated with it.
long epicsStdCall macPopScope(MAC_HANDLE *handle)
Retrieve the last pushed scope (like stack operations)
long epicsStdCall macCreateHandle(MAC_HANDLE **pHandle, const char *pairs[])
Creates a new macro substitution context.
std::string macroReplacements
Text macro substitution routines.
int main(int argc, char **argv)
LIBCOM_API long epicsStdCall macInstallMacros(MAC_HANDLE *handle, char *pairs[])
Install set of {name, value} pairs as definitions.
char string[MAX_BUFFER_SIZE]
long epicsStdCall macPushScope(MAC_HANDLE *handle)
Marks the start of a new scoping level.