VirtualBox

source: kBuild/trunk/src/kmk/commands.c@ 2125

Last change on this file since 2125 was 2027, checked in by bird, 16 years ago

kmk/commands.c: delete multi target siblings not only the head.

  • Property svn:eol-style set to native
File size: 19.9 KB
Line 
1/* Command processing for GNU Make.
2Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
31998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software
4Foundation, Inc.
5This file is part of GNU Make.
6
7GNU Make is free software; you can redistribute it and/or modify it under the
8terms of the GNU General Public License as published by the Free Software
9Foundation; either version 3 of the License, or (at your option) any later
10version.
11
12GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License along with
17this program. If not, see <http://www.gnu.org/licenses/>. */
18
19#include "make.h"
20#include "dep.h"
21#include "filedef.h"
22#include "variable.h"
23#include "job.h"
24#include "commands.h"
25#ifdef WINDOWS32
26#include <windows.h>
27#include "w32err.h"
28#endif
29#ifdef CONFIG_WITH_LAZY_DEPS_VARS
30# include <assert.h>
31#endif
32
33#if VMS
34# define FILE_LIST_SEPARATOR ','
35#else
36# define FILE_LIST_SEPARATOR ' '
37#endif
38
39int remote_kill (int id, int sig);
40
41#ifndef HAVE_UNISTD_H
42int getpid ();
43#endif
44
45
46/* Set FILE's automatic variables up. */
47
48void
49#if defined(CONFIG_WITH_COMMANDS_FUNC) || defined (CONFIG_WITH_DOT_MUST_MAKE)
50set_file_variables (struct file *file, int called_early)
51#else
52set_file_variables (struct file *file)
53#endif
54{
55 const struct dep *d;
56 const char *at, *percent, *star, *less;
57#ifdef CONFIG_WITH_STRCACHE2
58 const char *org_stem = file->stem;
59#endif
60
61#ifndef NO_ARCHIVES
62 /* If the target is an archive member `lib(member)',
63 then $@ is `lib' and $% is `member'. */
64
65 if (ar_name (file->name))
66 {
67 unsigned int len;
68 const char *cp;
69 char *p;
70
71 cp = strchr (file->name, '(');
72 p = alloca (cp - file->name + 1);
73 memcpy (p, file->name, cp - file->name);
74 p[cp - file->name] = '\0';
75 at = p;
76 len = strlen (cp + 1);
77 p = alloca (len);
78 memcpy (p, cp + 1, len - 1);
79 p[len - 1] = '\0';
80 percent = p;
81 }
82 else
83#endif /* NO_ARCHIVES. */
84 {
85 at = file->name;
86 percent = "";
87 }
88
89 /* $* is the stem from an implicit or static pattern rule. */
90 if (file->stem == 0)
91 {
92 /* In Unix make, $* is set to the target name with
93 any suffix in the .SUFFIXES list stripped off for
94 explicit rules. We store this in the `stem' member. */
95 const char *name;
96 unsigned int len;
97
98#ifndef NO_ARCHIVES
99 if (ar_name (file->name))
100 {
101 name = strchr (file->name, '(') + 1;
102 len = strlen (name) - 1;
103 }
104 else
105#endif
106 {
107 name = file->name;
108#ifndef CONFIG_WITH_STRCACHE2
109 len = strlen (name);
110#else
111 len = strcache2_get_len (&file_strcache, name);
112#endif
113 }
114
115#ifndef CONFIG_WITH_STRCACHE2
116 for (d = enter_file (strcache_add (".SUFFIXES"))->deps; d ; d = d->next)
117 {
118 unsigned int slen = strlen (dep_name (d));
119#else
120 for (d = enter_file (suffixes_strcached)->deps; d ; d = d->next)
121 {
122 unsigned int slen = strcache2_get_len (&file_strcache, dep_name (d));
123#endif
124 if (len > slen && strneq (dep_name (d), name + (len - slen), slen))
125 {
126 file->stem = strcache_add_len (name, len - slen);
127 break;
128 }
129 }
130 if (d == 0)
131 file->stem = "";
132 }
133 star = file->stem;
134
135 /* $< is the first not order-only dependency. */
136 less = "";
137 for (d = file->deps; d != 0; d = d->next)
138 if (!d->ignore_mtime)
139 {
140 less = dep_name (d);
141 break;
142 }
143
144 if (file->cmds == default_file->cmds)
145 /* This file got its commands from .DEFAULT.
146 In this case $< is the same as $@. */
147 less = at;
148
149#define DEFINE_VARIABLE(name, len, value) \
150 (void) define_variable_for_file (name,len,value,o_automatic,0,file)
151
152 /* Define the variables. */
153
154#ifndef CONFIG_WITH_RDONLY_VARIABLE_VALUE
155 DEFINE_VARIABLE ("<", 1, less);
156 DEFINE_VARIABLE ("*", 1, star);
157 DEFINE_VARIABLE ("@", 1, at);
158 DEFINE_VARIABLE ("%", 1, percent);
159#else /* CONFIG_WITH_RDONLY_VARIABLE_VALUE */
160# define DEFINE_VARIABLE_RO_VAL(name, len, value, value_len) \
161 define_variable_in_set((name), (len), (value), (value_len), -1, \
162 (o_automatic), 0, (file)->variables->set, NILF)
163
164 if (*less == '\0')
165 DEFINE_VARIABLE_RO_VAL ("<", 1, "", 0);
166 else if (less != at || at == file->name)
167 DEFINE_VARIABLE_RO_VAL ("<", 1, less, strcache_get_len (less));
168 else
169 DEFINE_VARIABLE ("<", 1, less);
170
171 if (*star == '\0')
172 DEFINE_VARIABLE_RO_VAL ("*", 1, "", 0);
173 else if (file->stem != org_stem)
174 DEFINE_VARIABLE_RO_VAL ("*", 1, star, strcache_get_len (star));
175 else
176 DEFINE_VARIABLE ("*", 1, star);
177
178 if (at == file->name)
179 DEFINE_VARIABLE_RO_VAL ("@", 1, at, strcache_get_len (at));
180 else
181 DEFINE_VARIABLE ("@", 1, at);
182
183 if (*percent == '\0')
184 DEFINE_VARIABLE_RO_VAL ("%", 1, "", 0);
185 else
186 DEFINE_VARIABLE ("%", 1, percent);
187#endif /* CONFIG_WITH_RDONLY_VARIABLE_VALUE */
188
189#if defined(CONFIG_WITH_COMMANDS_FUNC) || defined (CONFIG_WITH_DOT_MUST_MAKE)
190 /* The $^, $+, $? and $| variables should not be set if we're called
191 early by a .MUST_MAKE invocation or $(commands ). */
192 if (called_early)
193 return;
194#endif
195
196 /* Compute the values for $^, $+, $?, and $|. */
197#ifdef CONFIG_WITH_LAZY_DEPS_VARS
198 /* Lazy doesn't work for double colon rules with multiple files with
199 commands, nor for files that has been thru rehash_file() (vpath). */
200 if ( ( file->double_colon
201 && ( file->double_colon != file
202 || file->last != file))
203 || file->name != file->hname) /* XXX: Rehashed files should be fixable! */
204#endif
205 {
206 static char *plus_value=0, *bar_value=0, *qmark_value=0;
207 static unsigned int plus_max=0, bar_max=0, qmark_max=0;
208
209 unsigned int qmark_len, plus_len, bar_len;
210 char *cp;
211 char *caret_value;
212 char *qp;
213 char *bp;
214 unsigned int len;
215
216 /* Compute first the value for $+, which is supposed to contain
217 duplicate dependencies as they were listed in the makefile. */
218
219 plus_len = 0;
220 for (d = file->deps; d != 0; d = d->next)
221 if (! d->ignore_mtime)
222#ifndef CONFIG_WITH_STRCACHE2
223 plus_len += strlen (dep_name (d)) + 1;
224#else
225 plus_len += strcache2_get_len (&file_strcache, dep_name (d)) + 1;
226#endif
227 if (plus_len == 0)
228 plus_len++;
229
230 if (plus_len > plus_max)
231 plus_value = xrealloc (plus_value, plus_max = plus_len);
232 cp = plus_value;
233
234 qmark_len = plus_len + 1; /* Will be this or less. */
235 for (d = file->deps; d != 0; d = d->next)
236 if (! d->ignore_mtime)
237 {
238 const char *c = dep_name (d);
239
240#ifndef NO_ARCHIVES
241 if (ar_name (c))
242 {
243 c = strchr (c, '(') + 1;
244 len = strlen (c) - 1;
245 }
246 else
247#endif
248#ifndef CONFIG_WITH_STRCACHE2
249 len = strlen (c);
250#else
251 len = strcache2_get_len (&file_strcache, c);
252#endif
253
254 memcpy (cp, c, len);
255 cp += len;
256 *cp++ = FILE_LIST_SEPARATOR;
257 if (! d->changed)
258 qmark_len -= len + 1; /* Don't space in $? for this one. */
259 }
260
261 /* Kill the last space and define the variable. */
262
263 cp[cp > plus_value ? -1 : 0] = '\0';
264 DEFINE_VARIABLE ("+", 1, plus_value);
265
266 /* Make sure that no dependencies are repeated. This does not
267 really matter for the purpose of updating targets, but it
268 might make some names be listed twice for $^ and $?. */
269
270 uniquize_deps (file->deps);
271
272 bar_len = 0;
273 for (d = file->deps; d != 0; d = d->next)
274 if (d->ignore_mtime)
275#ifndef CONFIG_WITH_STRCACHE2
276 bar_len += strlen (dep_name (d)) + 1;
277#else
278 bar_len += strcache2_get_len (&file_strcache, dep_name (d)) + 1;
279#endif
280 if (bar_len == 0)
281 bar_len++;
282
283 /* Compute the values for $^, $?, and $|. */
284
285 cp = caret_value = plus_value; /* Reuse the buffer; it's big enough. */
286
287 if (qmark_len > qmark_max)
288 qmark_value = xrealloc (qmark_value, qmark_max = qmark_len);
289 qp = qmark_value;
290
291 if (bar_len > bar_max)
292 bar_value = xrealloc (bar_value, bar_max = bar_len);
293 bp = bar_value;
294
295 for (d = file->deps; d != 0; d = d->next)
296 {
297 const char *c = dep_name (d);
298
299#ifndef NO_ARCHIVES
300 if (ar_name (c))
301 {
302 c = strchr (c, '(') + 1;
303 len = strlen (c) - 1;
304 }
305 else
306#endif
307#ifndef CONFIG_WITH_STRCACHE2
308 len = strlen (c);
309#else
310 len = strcache2_get_len (&file_strcache, c);
311#endif
312
313 if (d->ignore_mtime)
314 {
315 memcpy (bp, c, len);
316 bp += len;
317 *bp++ = FILE_LIST_SEPARATOR;
318 }
319 else
320 {
321 memcpy (cp, c, len);
322 cp += len;
323 *cp++ = FILE_LIST_SEPARATOR;
324 if (d->changed)
325 {
326 memcpy (qp, c, len);
327 qp += len;
328 *qp++ = FILE_LIST_SEPARATOR;
329 }
330 }
331 }
332
333 /* Kill the last spaces and define the variables. */
334
335 cp[cp > caret_value ? -1 : 0] = '\0';
336 DEFINE_VARIABLE ("^", 1, caret_value);
337
338 qp[qp > qmark_value ? -1 : 0] = '\0';
339 DEFINE_VARIABLE ("?", 1, qmark_value);
340
341 bp[bp > bar_value ? -1 : 0] = '\0';
342 DEFINE_VARIABLE ("|", 1, bar_value);
343 }
344#ifdef CONFIG_WITH_LAZY_DEPS_VARS
345 else
346 {
347 /* Make a copy of the current dependency chain for later use in
348 potential $(dep-pluss $@) calls. Then drop duplicate deps. */
349
350 /* assert (file->org_deps == NULL); - FIXME? */
351 free_dep_chain (file->org_deps);
352 file->org_deps = copy_dep_chain (file->deps);
353
354 uniquize_deps (file->deps);
355 }
356#endif /* CONFIG_WITH_LAZY_DEPS_VARS */
357#undef DEFINE_VARIABLE
358}
359
360
361/* Chop CMDS up into individual command lines if necessary.
362 Also set the `lines_flags' and `any_recurse' members. */
363
364void
365chop_commands (struct commands *cmds)
366{
367 const char *p;
368 unsigned int nlines, idx;
369 char **lines;
370
371 /* If we don't have any commands,
372 or we already parsed them, never mind. */
373
374 if (!cmds || cmds->command_lines != 0)
375 return;
376
377 /* Chop CMDS->commands up into lines in CMDS->command_lines.
378 Also set the corresponding CMDS->lines_flags elements,
379 and the CMDS->any_recurse flag. */
380
381 nlines = 5;
382 lines = xmalloc (5 * sizeof (char *));
383 idx = 0;
384 p = cmds->commands;
385 while (*p != '\0')
386 {
387 const char *end = p;
388 find_end:;
389 end = strchr (end, '\n');
390 if (end == 0)
391 end = p + strlen (p);
392 else if (end > p && end[-1] == '\\')
393 {
394 int backslash = 1;
395 const char *b;
396 for (b = end - 2; b >= p && *b == '\\'; --b)
397 backslash = !backslash;
398 if (backslash)
399 {
400 ++end;
401 goto find_end;
402 }
403 }
404
405 if (idx == nlines)
406 {
407 nlines += 2;
408 lines = xrealloc (lines, nlines * sizeof (char *));
409 }
410 lines[idx++] = savestring (p, end - p);
411 p = end;
412 if (*p != '\0')
413 ++p;
414 }
415
416 if (idx != nlines)
417 {
418 nlines = idx;
419 lines = xrealloc (lines, nlines * sizeof (char *));
420 }
421
422 cmds->ncommand_lines = nlines;
423 cmds->command_lines = lines;
424
425 cmds->any_recurse = 0;
426#ifndef CONFIG_WITH_COMMANDS_FUNC
427 cmds->lines_flags = xmalloc (nlines);
428#else
429 cmds->lines_flags = xmalloc (nlines * sizeof (cmds->lines_flags[0]));
430#endif
431 for (idx = 0; idx < nlines; ++idx)
432 {
433 int flags = 0;
434
435 for (p = lines[idx];
436#ifndef CONFIG_WITH_COMMANDS_FUNC
437 isblank ((unsigned char)*p) || *p == '-' || *p == '@' || *p == '+';
438#else
439 isblank ((unsigned char)*p) || *p == '-' || *p == '@' || *p == '+' || *p == '%';
440#endif
441 ++p)
442 switch (*p)
443 {
444 case '+':
445 flags |= COMMANDS_RECURSE;
446 break;
447 case '@':
448 flags |= COMMANDS_SILENT;
449 break;
450 case '-':
451 flags |= COMMANDS_NOERROR;
452 break;
453#ifdef CONFIG_WITH_COMMANDS_FUNC
454 case '%':
455 flags |= COMMAND_GETTER_SKIP_IT;
456 break;
457#endif
458 }
459
460 /* If no explicit '+' was given, look for MAKE variable references. */
461 if (!(flags & COMMANDS_RECURSE)
462#ifndef KMK
463 && (strstr (p, "$(MAKE)") != 0 || strstr (p, "${MAKE}") != 0))
464#else
465 && (strstr (p, "$(KMK)") != 0 || strstr (p, "${KMK}") != 0 ||
466 strstr (p, "$(MAKE)") != 0 || strstr (p, "${MAKE}") != 0))
467#endif
468 flags |= COMMANDS_RECURSE;
469
470#ifdef CONFIG_WITH_KMK_BUILTIN
471 /* check if kmk builtin command */
472 if (!strncmp(p, "kmk_builtin_", sizeof("kmk_builtin_") - 1))
473 flags |= COMMANDS_KMK_BUILTIN;
474#endif
475
476 cmds->lines_flags[idx] = flags;
477 cmds->any_recurse |= flags & COMMANDS_RECURSE;
478 }
479}
480
481
482/* Execute the commands to remake FILE. If they are currently executing,
483 return or have already finished executing, just return. Otherwise,
484 fork off a child process to run the first command line in the sequence. */
485
486void
487execute_file_commands (struct file *file)
488{
489 const char *p;
490
491 /* Don't go through all the preparations if
492 the commands are nothing but whitespace. */
493
494 for (p = file->cmds->commands; *p != '\0'; ++p)
495 if (!isspace ((unsigned char)*p) && *p != '-' && *p != '@')
496 break;
497 if (*p == '\0')
498 {
499 /* If there are no commands, assume everything worked. */
500#ifdef CONFIG_WITH_EXTENDED_NOTPARALLEL
501 file->command_flags |= COMMANDS_NO_COMMANDS;
502#endif
503 set_command_state (file, cs_running);
504 file->update_status = 0;
505 notice_finished_file (file);
506 return;
507 }
508
509 /* First set the automatic variables according to this file. */
510
511 initialize_file_variables (file, 0);
512
513#if defined(CONFIG_WITH_COMMANDS_FUNC) || defined (CONFIG_WITH_DOT_MUST_MAKE)
514 set_file_variables (file, 0 /* final call */);
515#else
516 set_file_variables (file);
517#endif
518
519 /* Start the commands running. */
520 new_job (file);
521}
522
523
524/* This is set while we are inside fatal_error_signal,
525 so things can avoid nonreentrant operations. */
526
527int handling_fatal_signal = 0;
528
529/* Handle fatal signals. */
530
531RETSIGTYPE
532fatal_error_signal (int sig)
533{
534#ifdef __MSDOS__
535 extern int dos_status, dos_command_running;
536
537 if (dos_command_running)
538 {
539 /* That was the child who got the signal, not us. */
540 dos_status |= (sig << 8);
541 return;
542 }
543 remove_intermediates (1);
544 exit (EXIT_FAILURE);
545#else /* not __MSDOS__ */
546#ifdef _AMIGA
547 remove_intermediates (1);
548 if (sig == SIGINT)
549 fputs (_("*** Break.\n"), stderr);
550
551 exit (10);
552#else /* not Amiga */
553#if defined (WINDOWS32) && !defined (CONFIG_NEW_WIN32_CTRL_EVENT)
554 extern HANDLE main_thread;
555
556 /* Windows creates a sperate thread for handling Ctrl+C, so we need
557 to suspend the main thread, or else we will have race conditions
558 when both threads call reap_children. */
559 if (main_thread)
560 {
561 DWORD susp_count = SuspendThread (main_thread);
562
563 if (susp_count != 0)
564 fprintf (stderr, "SuspendThread: suspend count = %ld\n", susp_count);
565 else if (susp_count == (DWORD)-1)
566 {
567 DWORD ierr = GetLastError ();
568
569 fprintf (stderr, "SuspendThread: error %ld: %s\n",
570 ierr, map_windows32_error_to_string (ierr));
571 }
572 }
573#endif
574 handling_fatal_signal = 1;
575
576 /* Set the handling for this signal to the default.
577 It is blocked now while we run this handler. */
578 signal (sig, SIG_DFL);
579
580 /* A termination signal won't be sent to the entire
581 process group, but it means we want to kill the children. */
582
583 if (sig == SIGTERM)
584 {
585 struct child *c;
586 for (c = children; c != 0; c = c->next)
587 if (!c->remote)
588 (void) kill (c->pid, SIGTERM);
589 }
590
591 /* If we got a signal that means the user
592 wanted to kill make, remove pending targets. */
593
594 if (sig == SIGTERM || sig == SIGINT
595#ifdef SIGHUP
596 || sig == SIGHUP
597#endif
598#ifdef SIGQUIT
599 || sig == SIGQUIT
600#endif
601 )
602 {
603 struct child *c;
604
605 /* Remote children won't automatically get signals sent
606 to the process group, so we must send them. */
607 for (c = children; c != 0; c = c->next)
608 if (c->remote)
609 (void) remote_kill (c->pid, sig);
610
611 for (c = children; c != 0; c = c->next)
612 delete_child_targets (c);
613
614 /* Clean up the children. We don't just use the call below because
615 we don't want to print the "Waiting for children" message. */
616 while (job_slots_used > 0)
617 reap_children (1, 0);
618 }
619 else
620 /* Wait for our children to die. */
621 while (job_slots_used > 0)
622 reap_children (1, 1);
623
624 /* Delete any non-precious intermediate files that were made. */
625
626 remove_intermediates (1);
627#ifdef SIGQUIT
628 if (sig == SIGQUIT)
629 /* We don't want to send ourselves SIGQUIT, because it will
630 cause a core dump. Just exit instead. */
631 exit (EXIT_FAILURE);
632#endif
633
634#ifdef WINDOWS32
635# ifndef CONFIG_NEW_WIN32_CTRL_EVENT
636 if (main_thread)
637 CloseHandle (main_thread);
638# endif /* !CONFIG_NEW_WIN32_CTRL_EVENT */
639 /* Cannot call W32_kill with a pid (it needs a handle). The exit
640 status of 130 emulates what happens in Bash. */
641 exit (130);
642#else
643 /* Signal the same code; this time it will really be fatal. The signal
644 will be unblocked when we return and arrive then to kill us. */
645 if (kill (getpid (), sig) < 0)
646 pfatal_with_name ("kill");
647#endif /* not WINDOWS32 */
648#endif /* not Amiga */
649#endif /* not __MSDOS__ */
650}
651
652
653/* Delete FILE unless it's precious or not actually a file (phony),
654 and it has changed on disk since we last stat'd it. */
655
656static void
657delete_target (struct file *file, const char *on_behalf_of)
658{
659 struct stat st;
660 int e;
661
662 if (file->precious || file->phony)
663 return;
664#ifdef CONFIG_WITH_EXPLICIT_MULTITARGET
665 assert (!file->multi_maybe);
666#endif
667
668#ifndef NO_ARCHIVES
669 if (ar_name (file->name))
670 {
671 time_t file_date = (file->last_mtime == NONEXISTENT_MTIME
672 ? (time_t) -1
673 : (time_t) FILE_TIMESTAMP_S (file->last_mtime));
674 if (ar_member_date (file->name) != file_date)
675 {
676 if (on_behalf_of)
677 error (NILF, _("*** [%s] Archive member `%s' may be bogus; not deleted"),
678 on_behalf_of, file->name);
679 else
680 error (NILF, _("*** Archive member `%s' may be bogus; not deleted"),
681 file->name);
682 }
683 return;
684 }
685#endif
686
687 EINTRLOOP (e, stat (file->name, &st));
688 if (e == 0
689 && S_ISREG (st.st_mode)
690 && FILE_TIMESTAMP_STAT_MODTIME (file->name, st) != file->last_mtime)
691 {
692 if (on_behalf_of)
693 error (NILF, _("*** [%s] Deleting file `%s'"), on_behalf_of, file->name);
694 else
695 error (NILF, _("*** Deleting file `%s'"), file->name);
696 if (unlink (file->name) < 0
697 && errno != ENOENT) /* It disappeared; so what. */
698 perror_with_name ("unlink: ", file->name);
699 }
700}
701
702
703/* Delete all non-precious targets of CHILD unless they were already deleted.
704 Set the flag in CHILD to say they've been deleted. */
705
706void
707delete_child_targets (struct child *child)
708{
709 struct dep *d;
710
711 if (child->deleted)
712 return;
713
714 /* Delete the target file if it changed. */
715 delete_target (child->file, NULL);
716
717 /* Also remove any non-precious targets listed in the `also_make' member. */
718 for (d = child->file->also_make; d != 0; d = d->next)
719 delete_target (d->file, child->file->name);
720
721#ifdef CONFIG_WITH_EXPLICIT_MULTITARGET
722 /* Also remove any multi target siblings, except for the 'maybe' ones (we
723 handle that here) and precious ones (delete_target deals with that).
724 Note that CHILD is always the multi target head (see remake.c). */
725 if (child->file == child->file->multi_head)
726 {
727 struct file *f2;
728 for (f2 = child->file->multi_next; f2; f2 = f2->multi_next)
729 if (!f2->multi_maybe)
730 delete_target (f2, child->file->name);
731 }
732#endif
733
734 child->deleted = 1;
735}
736
737
738/* Print out the commands in CMDS. */
739
740void
741print_commands (const struct commands *cmds)
742{
743 const char *s;
744
745 fputs (_("# recipe to execute"), stdout);
746
747 if (cmds->fileinfo.filenm == 0)
748 puts (_(" (built-in):"));
749 else
750 printf (_(" (from `%s', line %lu):\n"),
751 cmds->fileinfo.filenm, cmds->fileinfo.lineno);
752
753 s = cmds->commands;
754 while (*s != '\0')
755 {
756 const char *end;
757
758 end = strchr (s, '\n');
759 if (end == 0)
760 end = s + strlen (s);
761
762 printf ("%c%.*s\n", cmd_prefix, (int) (end - s), s);
763
764 s = end + (end[0] == '\n');
765 }
766}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette