1 /*****************************************************************************/
2 /*                                                                           */
3 /*                 (C) Copyright 1994-1996  Alberto Pasquale                 */
4 /*                 Portions (C) Copyright 1999 Per Lundberg                  */
5 /*                                                                           */
6 /*                   A L L   R I G H T S   R E S E R V E D                   */
7 /*                                                                           */
8 /*****************************************************************************/
9 /*                                                                           */
10 /*   How to contact the author:  Alberto Pasquale of 2:332/504@fidonet       */
11 /*                               Viale Verdi 106                             */
12 /*                               41100 Modena                                */
13 /*                               Italy                                       */
14 /*                                                                           */
15 /*****************************************************************************/
16 
17 #include "apgenlib.hpp"
18 #include <string.h>
19 #include <stdarg.h>
20 #include <stdlib.h>
21 #if !defined (__FreeBSD__)
22 #  include <malloc.h>
23 #endif
24 
StrQTok(char * & c)25 static char *StrQTok (char *&c)
26 {
27     char *start;
28 
29     c += strspn (c, " \t\n");    // skip blank
30     if (*c == '\0')
31         return NULL;            // return NULL if no token available
32 
33     start = c;
34 
35     BOOL InQuotes = FALSE;
36     BOOL TokEnd = FALSE;
37 
38     while ((*c) && !TokEnd) {
39         switch (*c) {
40             case ' ':
41             case '\t':
42             case '\n':
43                 if (InQuotes)
44                     c ++;
45                 else
46                     TokEnd = TRUE;
47                 break;
48             case '"':
49                 InQuotes = !InQuotes;
50                 c ++;
51                 break;
52             default:
53                 c ++;
54                 break;
55         }
56     }
57 
58     if (*c) {
59         *c = '\0';      // terminate token
60         c++;
61         c += strspn (c, " \t\n");  // advance c to next token or terminating NULL
62     }
63 
64     return start;
65 }
66 
67 
68 #define _Quotes_Delimited_ TRUE
69 
70 
71 // Builds command line, one space between tokens, double trailing zero.
72 // Triple trailing zero in case of empty args string.
73 // Just to be sure, a triple zero is always appended.
74 
BuildCmd(char * cmdline,uint cmdlinesize,int nargs,char const * args[],BOOL delimited=FALSE)75 static void BuildCmd (char *cmdline, uint cmdlinesize, int nargs,
76                       char const *args[], BOOL delimited = FALSE)
77 {
78     char *p = cmdline;
79     *p = '\0';              // init empty command line string
80 
81     if (nargs == 0)         // nothing to do
82         return;
83 
84     if (args[0][0] == '\0')     // empty command name
85         return;
86 
87     cmdlinesize -= 3;           // leave space for trailing zeros
88 
89     if (strlen (args[0]) > cmdlinesize)    // too long command name
90         return;
91 
92     p = fl_stpcpy (p, args[0]);        // command name
93 
94     for (int i = 1; i < nargs; i++) {
95         if (((p - cmdline) + 1 + strlen (args[i]) + (delimited ? 2 : 0)) > cmdlinesize)
96             break;
97 
98         *p++ = ' ';
99 
100         if (delimited)
101             *p++ = '"';
102         p = fl_stpcpy (p, args[i]);
103         if (delimited)
104             *p++ = '"';
105     }
106 
107     *p++ = '\0';        // assure double trailing zero in any case
108     *p++ = '\0';        // double trailing zero
109     *p++ = '\0';
110 }
111 
RunCmd(const char * cmd,RCShow rcs,const char * prmlst,...)112 int RunCmd (const char *cmd, RCShow rcs, const char *prmlst, ...)
113 {
114     #define MAXARGS 21
115     #define MAXSUBS 10
116 
117     char const *subs[MAXSUBS];
118     char const *args[MAXARGS];
119     int j;
120 
121     if (!cmd)
122         return -1;
123 
124     int nsubs = __min (strlen (prmlst), MAXSUBS);
125 
126     va_list vargs;
127     va_start (vargs, prmlst);
128     for (j = 0; j < nsubs; j++)    // init prm substitutions
129         subs[j] = va_arg (vargs, char *);
130     va_end (vargs);
131 
132     char *workline = newcpy (cmd);
133     char *c = workline;
134 
135     int i = 0;
136     args[i++] = StrQTok (c);  // Prg name
137 
138     if (args[0] == NULL) {
139         if (rcs)
140             rcs (RC_EMPTY);
141         delete[] workline;
142         return -1;
143     }
144 
145     while (i < MAXARGS-1) {
146         char *arg = StrQTok (c);
147         if (!arg)
148             break;
149         if ((strlen (arg) == 2) && (arg[0] == '%')) {    // can be a substitution parameter
150             BOOL found = FALSE;
151             for (j = 0; j < nsubs; j ++)
152                 if (arg[1] == prmlst[j]) {
153                     args[i++] = subs[j];
154                     found = TRUE;
155                     break;
156                 }
157             if (found)
158                 continue;
159         }
160         args[i++] = arg;
161     }
162 
163     int nargs = i;
164     args[i] = NULL;  // necessary for spawn function
165 
166     char *rescmdline = new char[4 * PATH_MAX];
167     BuildCmd (rescmdline, 4 * PATH_MAX, nargs, args);
168     if (rcs)
169         rcs (RC_DOING, rescmdline);
170 
171     int code = system (rescmdline);
172 
173     delete[] rescmdline;
174     delete[] workline;
175 
176     if (rcs)
177         rcs (RC_EXIT, code);
178 
179     return code;
180 
181     #undef MAXSUBS
182     #undef MAXARGS
183 }
184