1 /*************************************************************************
3 * m a k e : m a k e . c
5 * Do the actual making for make plus system dependent stuff
6 *========================================================================
10 * --- -------- ---------------------------------------------------- ---
12 * 2 01.07.89 $<,$* bugs fixed RAL
13 * 3 23.08.89 (time_t)time((time_t*)0) bug fixed, N_EXISTS added RAL
14 * 4 30.08.89 leading sp. in cmd. output eliminated, indention ch. PSH,RAL
15 * 5 03.09.89 :: time fixed, error output -> stderr, N_ERROR intr.
16 * fixed LZ elimintaed RAL
17 * 6 07.09.89 implmacro, DF macros,debug stuff added RAL
18 * 7 09.09.89 tos support added PHH,RAL
19 * 8 17.09.89 make1 arg. fixed, N_EXEC introduced RAL
20 * ------------ Version 2.0 released ------------------------------- RAL
21 * 18.05.90 fixed -n bug with silent rules. (Now echos them.) PAN
23 *************************************************************************/
29 _PROTOTYPE(static void tellstatus
, (FILE *out
, char *name
, int status
));
34 * Exec a shell that returns exit status correctly (/bin/esh).
35 * The standard EON shell returns the process number of the last
36 * async command, used by the debugger (ugg).
37 * [exec on eon is like a fork+exec on unix]
39 int dosh(string
, shell
)
46 return system(string
);
49 return Tosexec(string
);
52 return ((number
= execl(shell
, shell
,"-c", string
, 0)) == -1) ?
53 -1: /* couldn't start the shell */
54 wait(number
); /* return its exit status */
60 if ((number
= os9fork(shell
, strlen(string
), string
, 0, 0, 0)) == -1)
61 return -1; /* Couldn't start a shell */
63 if ((pid
= wait(&status
)) == -1)
64 return -1; /* child already died!?!? */
65 } while (pid
!= number
);
74 * Make a file look very outdated after an error trying to make it.
75 * Don't remove, this keeps hard links intact. (kjb)
77 int makeold(name
) char *name
;
81 a
.actime
= a
.modtime
= 0; /* The epoch */
83 return utime(name
, &a
);
88 static void tellstatus(out
, name
, status
)
95 fprintf(out
, "%s in %s: ",
96 name
, getcwd(cwd
, sizeof(cwd
)) == NULL
? "?" : cwd
);
98 if (WIFEXITED(status
)) {
99 fprintf(out
, "Exit code %d", WEXITSTATUS(status
));
101 fprintf(out
, "Signal %d%s",
102 WTERMSIG(status
), status
& 0x80 ? " - core dumped" : "");
108 * Do commands to make a target
116 register struct cmd
*cp
;
123 if (*(shell
= getmacro("SHELL")) == '\0')
134 shell
= "DESKTOP"; /* TOS has no shell */
137 for (cp
= lp
->l_cmd
; cp
; cp
= cp
->c_next
) {
139 strcpy(str1
, cp
->c_cmd
);
145 while ((*q
== '@') || (*q
== '-')) {
146 if (*q
== '@') /* Specific silent */
148 else /* Specific ignore */
150 if (!domake
) putchar(*q
); /* Show all characters. */
151 q
++; /* Not part of the command */
155 if (*p
== '\n' && p
[1] != '\0') {
157 if (!ssilent
|| !domake
)
158 fputs("\\\n", stdout
);
160 else if (!ssilent
|| !domake
)
163 if (!ssilent
|| !domake
)
166 if (domake
|| expmake
) { /* Get the shell to execute it */
168 if ((estat
= dosh(q
, shell
)) != 0) {
170 fatal("Couldn't execute %s", shell
,0);
172 tellstatus(stdout
, myname
, estat
);
173 printf(" (Ignored)\n");
175 tellstatus(stderr
, myname
, estat
);
176 fprintf(stderr
, "\n");
177 if (!(np
->n_flag
& N_PREC
))
179 if (makeold(np
->n_name
) == 0)
180 fprintf(stderr
,"%s: made '%s' look old.\n", myname
, np
->n_name
);
182 if (unlink(np
->n_name
) == 0)
183 fprintf(stderr
,"%s: '%s' removed.\n", myname
, np
->n_name
);
185 if (!conterr
) exit(estat
!= 0);
186 np
->n_flag
|= N_ERROR
;
198 register struct line
*lp
;
200 for (lp
= np
->n_line
; lp
; lp
= lp
->l_next
)
206 * execute the command submitted by make,
207 * needed because TOS has no internal shell,
208 * so we use Pexec to do the job
209 * v 1.1 of 10/sep/89 by yeti
219 register char *help
, *help2
, c
;
220 register unsigned char l
=1;
221 char progname
[80], command
[255], plain
[15];
222 static char **envp
,*env
;
223 register int error
,i
;
225 /* generate strange TOS environment (RAL) */
226 for ( i
= 0, envp
= environ
; *envp
; envp
++) i
+= strlen(*envp
) +1;
227 if ((env
= malloc(i
+1)) == (char *)0)
228 fatal("No memory for TOS environment",(char *)0,0);
229 for ( envp
= environ
, help
= env
; *envp
; envp
++) {
230 strcpy ( help
, *envp
);
236 while((*help
++=*string
++) != ' '); /* progname is command name */
239 l
= strlen(string
); /* build option list */
240 command
[0] = l
; /* TOS likes it complicated */
241 strcpy(&command
[1],string
);
242 if ((error
= (int) Pexec(0,progname
,command
,env
)) != -33) {
247 /* could'nt find program, try to search the PATH */
248 if((help
=strrchr(progname
,'\\')) != (char *) 0) /* just the */
249 strcpy(plain
,++help
); /* name */
250 else if((help
=strrchr(progname
,'/')) != (char *) 0)
251 strcpy(plain
,++help
);
252 else if((help
=strrchr(progname
,':')) != (char *) 0)
253 strcpy(plain
,++help
);
255 strcpy(plain
,progname
);
257 if(*(help
=getmacro("PATH")) == '\0') {
263 { help2
= &progname
[-1];
265 while((c
=*help
++) != '\0' && i
<80 && c
!= DELM1
266 && c
!= DELM2
&& c
!= DELM3
)
269 strcpy(++help2
,plain
);
270 if((error
=(int) Pexec(0,progname
,command
,env
))!=-33) {
280 /* (stolen from ZOO -- thanks to Rahul Dehsi)
281 Function mstonix() accepts an MSDOS format date and time and returns
282 a **IX format time. No adjustment is done for timezone.
285 time_t mstonix (date
, time
)
286 unsigned int date
, time
;
288 int year
, month
, day
, hour
, min
, sec
, daycount
;
290 /* no. of days to beginning of month for each month */
291 static int dsboy
[12] = { 0, 31, 59, 90, 120, 151, 181, 212,
294 if (date
== 0 && time
== 0) /* special case! */
297 /* part of following code is common to zoolist.c */
298 year
= (((unsigned int) date
>> 9) & 0x7f) + 1980;
299 month
= ((unsigned int) date
>> 5) & 0x0f;
302 hour
= ((unsigned int) time
>> 11)& 0x1f;
303 min
= ((unsigned int) time
>> 5) & 0x3f;
304 sec
= ((unsigned int) time
& 0x1f) * 2;
306 /* DEBUG and leap year fixes thanks to Mark Alexander <uunet!amdahl!drivax!alexande>*/
308 printf ("mstonix: year=%d month=%d day=%d hour=%d min=%d sec=%d\n",
309 year
, month
, day
, hour
, min
, sec
);
311 /* Calculate days since 1970/01/01 */
312 daycount
= 365 * (year
- 1970) + /* days due to whole years */
313 (year
- 1969) / 4 + /* days due to leap years */
314 dsboy
[month
-1] + /* days since beginning of this year */
315 day
-1; /* days since beginning of month */
318 year
% 400 != 0 && month
>= 3) /* if this is a leap year and month */
319 daycount
++; /* is March or later, add a day */
321 /* Knowing the days, we can find seconds */
322 longtime
= daycount
* 24L * 60L * 60L +
323 hour
* 60L * 60L + min
* 60 + sec
;
330 * Some stuffing around to get the modified time of a file
331 * in an os9 file system
333 void getmdate(fd
, tbp
)
337 struct registers regs
;
338 static struct fildes fdbuf
;
344 regs
.rg_y
= sizeof (fdbuf
);
346 if (_os9(I_GETSTT
, ®s
) == -1) {
347 errno
= regs
.rg_b
& 0xff;
352 _strass(tbp
, fdbuf
.fd_date
, sizeof (fdbuf
.fd_date
));
353 tbp
->t_second
= 0; /* Files are only acurate to mins */
360 * Kludge routine to return an aproximation of how many
361 * seconds since 1980. Dates will be in order, but will not
369 acc
= tbp
->t_year
- 80; /* Baseyear is 1980 */
370 acc
= acc
* 12 + tbp
->t_month
;
371 acc
= acc
* 31 + tbp
->t_day
;
372 acc
= acc
* 24 + tbp
->t_hour
;
373 acc
= acc
* 60 + tbp
->t_minute
;
374 acc
= acc
* 60 + tbp
->t_second
;
381 * Get the current time in the internal format
389 if (getime(&tbuf
) < 0)
393 *tp
= cnvtime(&tbuf
);
401 * Get the modification time of a file. If the first
402 * doesn't exist, it's modtime is set to 0.
411 if (is_archive_ref(np
->n_name
)) {
412 r
= archive_stat(np
->n_name
, &info
);
414 r
= stat(np
->n_name
, &info
);
418 fatal("Can't open %s: %s", np
->n_name
, errno
);
421 np
->n_flag
&= ~N_EXISTS
;
423 np
->n_time
= info
.st_mtime
;
424 np
->n_flag
|= N_EXISTS
;
431 if((fd
=Fopen(np
->n_name
,0)) < 0) {
433 np
->n_flag
&= ~N_EXISTS
;
438 np
->n_time
= mstonix((unsigned int)fm
.date
,(unsigned int)fm
.time
);
439 np
->n_flag
|= N_EXISTS
;
446 if ((fd
= open(np
->n_name
, 0)) < 0) {
447 if (errno
!= ER_NOTF
)
448 fatal("Can't open %s: %s", np
->n_name
, errno
);
451 np
->n_flag
&= ~N_EXISTS
;
453 else if (getstat(fd
, &info
) < 0)
454 fatal("Can't getstat %s: %s", np
->n_name
, errno
);
456 np
->n_time
= info
.st_mod
;
457 np
->n_flag
|= N_EXISTS
;
466 if ((fd
= open(np
->n_name
, 0)) < 0) {
468 fatal("Can't open %s: %s", np
->n_name
, errno
);
471 np
->n_flag
&= ~N_EXISTS
;
473 else if (getmdate(fd
, &info
) < 0)
474 fatal("Can't getstat %s: %s", np
->n_name
, errno
);
476 np
->n_time
= cnvtime(&info
);
477 np
->n_flag
|= N_EXISTS
;
486 * Update the mod time of a file to now.
494 if (!domake
|| !silent
) printf("touch(%s)\n", np
->n_name
);
500 a
.actime
= a
.modtime
= time((time_t *)NULL
);
501 if (utime(np
->n_name
, &a
) < 0)
502 printf("%s: '%s' not touched - non-existant\n",
509 if((fd
=Fopen(np
->n_name
,0)) < 0) {
510 printf("%s: '%s' not touched - non-existant\n",
514 fm
.date
= Tgetdate();
515 fm
.time
= Tgettime();
521 if ((fd
= open(np
->n_name
, 0)) < 0)
522 printf("%s: '%s' not touched - non-existant\n",
533 * Strange that something almost as totally useless
534 * as this is easy to do in os9!
536 if ((fd
= open(np
->n_name
, S_IWRITE
)) < 0)
537 printf("%s: '%s' not touched - non-existant\n",
546 * Recursive routine to make a target.
552 register struct depend
*dp
;
553 register struct line
*lp
;
554 register struct depend
*qdp
;
555 time_t now
, t
, dtime
= 0;
556 bool dbgfirst
= TRUE
;
557 char *basename
= (char *) 0;
558 char *inputname
= (char *) 0;
560 if (np
->n_flag
& N_DONE
) {
561 if(dbginfo
) dbgprint(level
,np
,"already done");
565 modtime(np
); /* Gets modtime of this file */
567 while (time(&now
) == np
->n_time
) {
568 /* Time of target is equal to the current time. This bothers us, because
569 * we can't tell if it needs to be updated if we update a file it depends
570 * on within a second. So wait until the second is over.
576 for (lp
= np
->n_line
; lp
; lp
= lp
->l_next
)
580 dyndep(np
,&basename
,&inputname
);
583 if (!(np
->n_flag
& (N_TARG
| N_EXISTS
))) {
584 fprintf(stderr
,"%s: Don't know how to make %s\n", myname
, np
->n_name
);
586 np
->n_flag
|= N_ERROR
;
587 if (dbginfo
) dbgprint(level
,np
,"don't know how to make");
593 for (qdp
= (struct depend
*)0, lp
= np
->n_line
; lp
; lp
= lp
->l_next
) {
594 for (dp
= lp
->l_dep
; dp
; dp
= dp
->d_next
) {
595 if(dbginfo
&& dbgfirst
) {
596 dbgprint(level
,np
," {");
599 make(dp
->d_name
, level
+1);
600 if (np
->n_time
< dp
->d_name
->n_time
)
601 qdp
= newdep(dp
->d_name
, qdp
);
602 dtime
= max(dtime
, dp
->d_name
->n_time
);
603 if (dp
->d_name
->n_flag
& N_ERROR
) np
->n_flag
|= N_ERROR
;
604 if (dp
->d_name
->n_flag
& N_EXEC
) np
->n_flag
|= N_EXEC
;
606 if (!quest
&& (np
->n_flag
& N_DOUBLE
) &&
607 (np
->n_time
< dtime
|| !( np
->n_flag
& N_EXISTS
))) {
609 make1(np
, lp
, qdp
, basename
, inputname
); /* free()'s qdp */
611 qdp
= (struct depend
*)0;
612 if(execflag
) np
->n_flag
|= N_EXEC
;
616 np
->n_flag
|= N_DONE
;
623 else if ((np
->n_time
< dtime
|| !( np
->n_flag
& N_EXISTS
))
624 && !(np
->n_flag
& N_DOUBLE
)) {
626 make1(np
, (struct line
*)0, qdp
, basename
, inputname
); /* free()'s qdp */
628 if ( execflag
) np
->n_flag
|= N_EXEC
;
630 else if ( np
->n_flag
& N_EXEC
) {
636 if(np
->n_flag
& N_ERROR
)
637 dbgprint(level
,np
,"skipped because of error");
638 else if(np
->n_flag
& N_EXEC
)
639 dbgprint(level
,np
,"successfully made");
640 else dbgprint(level
,np
,"is up to date");
643 if(np
->n_flag
& N_ERROR
)
644 dbgprint(level
,(struct name
*)0,"} skipped because of error");
645 else if(np
->n_flag
& N_EXEC
)
646 dbgprint(level
,(struct name
*)0,"} successfully made");
647 else dbgprint(level
,(struct name
*)0,"} is up to date");
650 if (level
== 0 && !(np
->n_flag
& N_EXEC
))
651 printf("%s: '%s' is up to date\n", myname
, np
->n_name
);
659 void make1(np
, lp
, qdp
, basename
, inputname
)
662 register struct depend
*qdp
;
666 register struct depend
*dp
;
671 else if (!(np
->n_flag
& N_ERROR
)) {
675 inputname
= str1
; /* default */
676 if (ambigmac
) implmacros(np
,lp
,&basename
,&inputname
);
678 setDFmacro("<",inputname
);
682 setDFmacro("*",basename
);
684 for (dp
= qdp
; dp
; dp
= qdp
) {
686 l2
= strlen(dp
->d_name
->n_name
);
687 while (l1
+ 1 + l2
+1 > str1s
.len
)
691 strcat(str1
, dp
->d_name
->n_name
);
696 setDFmacro("@", np
->n_name
);
698 if (lp
) /* lp set if doing a :: rule */
705 void implmacros(np
,lp
, pbasename
,pinputname
)
708 char **pbasename
; /* Name without suffix */
714 register char *suff
; /* Old suffix */
719 /* get basename out of target name */
723 while ( *q
&& (q
< suff
|| !suff
)) *p
++ = *q
++;
725 if ((*pbasename
= (char *) malloc(strlen(str2
)+1)) == (char *)0 )
726 fatal("No memory for basename",(char *)0,0);
727 strcpy(*pbasename
,str2
);
728 baselen
= strlen(str2
);
736 for (dp
= llp
->l_dep
; dp
; dp
= dp
->d_next
) {
737 if( strncmp(*pbasename
,dp
->d_name
->n_name
,baselen
) == 0) {
738 *pinputname
= dp
->d_name
->n_name
;
742 *pinputname
= dp
->d_name
->n_name
;
750 #if NO_WE_DO_WANT_THIS_BASENAME
751 free(*pbasename
); /* basename ambiguous or no dependency file */
752 *pbasename
= (char *)0;
757 void dbgprint(level
,np
,comment
)
765 timep
= ctime(&np
->n_time
);
767 fputs(&timep
[4],stdout
);
769 else fputs(" ",stdout
);
771 while(level
--) fputs(" ",stdout
);
773 fputs(np
->n_name
,stdout
);
774 if (np
->n_flag
& N_DOUBLE
) fputs(" :: ",stdout
);
775 else fputs(" : ",stdout
);
777 fputs(comment
,stdout
);