source: rtems/cpukit/pppd/chat.c @ df49c60

4.104.114.84.9
Last change on this file since df49c60 was d0950ad, checked in by Joel Sherrill <joel.sherrill@…>, on Nov 30, 1999 at 10:12:50 PM

Added port of ppp-2.3.5 from Tomasz Domin <dot@…> of ComArch? SA.
Tomasz only tested this on the mpc823.

The official site for the original source for this PPP implementation is:

ftp://cs.anu.edu.au/pub/software/ppp

NOTE: As of 11/30/1999, the current version of this source is 2.3.10.

  • Property mode set to 100644
File size: 18.4 KB
Line 
1/*
2 *      Chat -- a program for automatic session establishment (i.e. dial
3 *              the phone and log in).
4 *
5 * Standard termination codes:
6 *  0 - successful completion of the script
7 *  1 - invalid argument, expect string too large, etc.
8 *  2 - error on an I/O operation or fatal error condition.
9 *  3 - timeout waiting for a simple string.
10 *  4 - the first string declared as "ABORT"
11 *  5 - the second string declared as "ABORT"
12 *  6 - ... and so on for successive ABORT strings.
13 *
14 *      This software is in the public domain.
15 *
16 * -----------------
17 *      added -T and -U option and \T and \U substitution to pass a phone
18 *      number into chat script. Two are needed for some ISDN TA applications.
19 *      Keith Dart <kdart@cisco.com>
20 *     
21 *
22 *      Added SAY keyword to send output to stderr.
23 *      This allows to turn ECHO OFF and to output specific, user selected,
24 *      text to give progress messages. This best works when stderr
25 *      exists (i.e.: pppd in nodetach mode).
26 *
27 *      Added HANGUP directives to allow for us to be called
28 *      back. When HANGUP is set to NO, chat will not hangup at HUP signal.
29 *      We rely on timeouts in that case.
30 *
31 *      Added CLR_ABORT to clear previously set ABORT string. This has been
32 *      dictated by the HANGUP above as "NO CARRIER" (for example) must be
33 *      an ABORT condition until we know the other host is going to close
34 *      the connection for call back. As soon as we have completed the
35 *      first stage of the call back sequence, "NO CARRIER" is a valid, non
36 *      fatal string. As soon as we got called back (probably get "CONNECT"),
37 *      we should re-arm the ABORT "NO CARRIER". Hence the CLR_ABORT command.
38 *      Note that CLR_ABORT packs the abort_strings[] array so that we do not
39 *      have unused entries not being reclaimed.
40 *
41 *      In the same vein as above, added CLR_REPORT keyword.
42 *
43 *      Allow for comments. Line starting with '#' are comments and are
44 *      ignored. If a '#' is to be expected as the first character, the
45 *      expect string must be quoted.
46 *
47 *
48 *              Francis Demierre <Francis@SwissMail.Com>
49 *              Thu May 15 17:15:40 MET DST 1997
50 *
51 *
52 *      Added -r "report file" switch & REPORT keyword.
53 *              Robert Geer <bgeer@xmission.com>
54 *
55 *      Added -s "use stderr" and -S "don't use syslog" switches.
56 *              June 18, 1997
57 *              Karl O. Pinc <kop@meme.com>
58 *
59 *
60 *      Added -e "echo" switch & ECHO keyword
61 *              Dick Streefland <dicks@tasking.nl>
62 *
63 *
64 *      Considerable updates and modifications by
65 *              Al Longyear <longyear@pobox.com>
66 *              Paul Mackerras <paulus@cs.anu.edu.au>
67 *
68 *
69 *      The original author is:
70 *
71 *              Karl Fox <karl@MorningStar.Com>
72 *              Morning Star Technologies, Inc.
73 *              1760 Zollinger Road
74 *              Columbus, OH  43221
75 *              (614)451-1883
76 *
77 *
78 */
79
80#ifndef lint
81/* static char rcsid[] = ""; */
82#endif
83
84#include <stdio.h>
85#include <ctype.h>
86#include <time.h>
87#include <fcntl.h>
88#include <signal.h>
89#include <errno.h>
90#include <string.h>
91#include <stdlib.h>
92#include <unistd.h>
93#include <sys/types.h>
94#include <sys/stat.h>
95#include <syslog.h>
96
97#undef  TERMIOS
98#define TERMIOS
99
100
101#include <termios.h>
102
103#define STR_LEN 1024
104char temp2[STR_LEN];
105
106#ifndef SIGTYPE
107#define SIGTYPE void
108#endif
109
110#undef __P
111#undef __V
112
113#ifdef __STDC__
114#include <stdarg.h>
115#define __V(x)  x
116#define __P(x)  x
117#else
118#include <varargs.h>
119#define __V(x)  (va_alist) va_dcl
120#define __P(x)  ()
121#define const
122#endif
123
124#ifndef O_NONBLOCK
125#define O_NONBLOCK      O_NDELAY
126#endif
127
128
129/*************** Micro getopt() *********************************************/
130#define OPTION(c,v)     (_O&2&&**v?*(*v)++:!c||_O&4?0:(!(_O&1)&& \
131                                (--c,++v),_O=4,c&&**v=='-'&&v[0][1]?*++*v=='-'\
132                                &&!v[0][1]?(--c,++v,0):(_O=2,*(*v)++):0))
133#define OPTARG(c,v)     (_O&2?**v||(++v,--c)?(_O=1,--c,*v++): \
134                                (_O=4,(char*)0):(char*)0)
135#define OPTONLYARG(c,v) (_O&2&&**v?(_O=1,--c,*v++):(char*)0)
136#define ARG(c,v)        (c?(--c,*v++):(char*)0)
137
138#if 0
139static int _O = 0;              /* Internal state */
140#endif
141/*************** Micro getopt() *********************************************/
142
143char *program_name;
144
145#define MAX_ABORTS              5
146#define MAX_REPORTS             5
147#define DEFAULT_CHAT_TIMEOUT    45
148#define fcntl(a, b,c ) 0
149#define MAX_TIMEOUTS 10
150
151int echo          = 0;
152int verbose       = 0;
153int to_log        = 1;
154int to_stderr     = 0;
155int Verbose       = 0;
156int quiet         = 0;
157int report        = 0;
158int exit_code     = 0;
159static int speed=0;
160char *report_file = (char *) 0;
161char *chat_file   = (char *) 0;
162char *phone_num   = (char *) 0;
163char *phone_num2  = (char *) 0;
164int chat_timeout       = DEFAULT_CHAT_TIMEOUT;
165static int timeout       = DEFAULT_CHAT_TIMEOUT;
166int have_tty_parameters = 0;
167
168#ifdef TERMIOS
169#define term_parms struct termios
170#define get_term_param(param) tcgetattr(modem_fd, param)
171#define set_term_param(param) tcsetattr(modem_fd, TCSANOW, param)
172struct termios saved_tty_parameters;
173#endif
174
175char *abort_string[MAX_ABORTS]={"BUSY","NO DIALTONE","NO CARRIER","NO ASWER","RINGING\r\n\r\nRINGING"};
176char *fail_reason = (char *)0,
177        fail_buffer[50];
178int n_aborts = MAX_ABORTS, abort_next = 0, timeout_next = 0, echo_next = 0;
179int clear_abort_next = 0;
180
181char *report_string[MAX_REPORTS] ;
182char  report_buffer[50] ;
183int n_reports = 0, report_next = 0, report_gathering = 0 ; 
184int clear_report_next = 0;
185
186int say_next = 0, hup_next = 0;
187
188void *dup_mem __P((void *b, size_t c));
189void *copy_of __P((char *s));
190/*
191SIGTYPE sigalrm __P((int signo));
192SIGTYPE sigint __P((int signo));
193SIGTYPE sigterm __P((int signo));
194SIGTYPE sighup __P((int signo));
195*/
196void unalarm __P((void));
197void init __P((void));
198void set_tty_parameters __P((void));
199void echo_stderr __P((int));
200void break_sequence __P((void));
201void terminate __P((int status));
202void do_file __P((char *chat_file));
203int  get_string __P((register char *string));
204int  put_string __P((register char *s));
205int  write_char __P((int c));
206int  put_char __P((int c));
207int  get_char __P((void));
208void chat_send __P((register char *s));
209char *character __P((int c));
210void chat_expect __P((register char *s));
211char *clean __P((register char *s, int sending));
212void break_sequence __P((void));
213void terminate __P((int status));
214void pack_array __P((char **array, int end));
215char *expect_strtok __P((char *, char *));
216int vfmtmsg __P((char *, int, const char *, va_list));  /* vsprintf++ */
217
218#if 0
219int usleep( long usec );                                  /* returns 0 if ok, else -1 */
220#endif
221   
222extern int input_fd,output_fd;
223
224int main __P((int, char *[]));
225
226void *dup_mem(b, c)
227void *b;
228size_t c;
229{
230    void *ans = malloc (c);
231    if (!ans)
232                return NULL;
233
234    memcpy (ans, b, c);
235    return ans;
236}
237
238void *copy_of (s)
239char *s;
240{
241    return dup_mem (s, strlen (s) + 1);
242}
243
244/*
245 * chat [ -v ] [-T number] [-U number] [ -t timeout ] [ -f chat-file ] \
246 * [ -r report-file ] \
247 *              [...[[expect[-say[-expect...]] say expect[-say[-expect]] ...]]]
248 *
249 *      Perform a UUCP-dialer-like chat script on stdin and stdout.
250 */
251char *getnextcommand(char **string)
252{
253        char *buf=*string,*res;
254        res=strchr(buf,'@');
255        if (res==NULL)
256                return NULL;
257        *res='\0';
258        *string=res+1;
259        return buf;
260}
261
262 
263extern int modem_fd;
264int
265        chatmain(argv)
266     char *argv;
267{
268    char *arg;
269        int i;
270        char *t;
271        exit_code=0;
272        speed=0;
273/*
274 * Default the report file to the stderr location
275 */
276/*    if (report_fp == NULL)
277        report_fp = stderr;
278*/
279    init();
280        while ( (arg = getnextcommand(&argv)) != NULL) {
281            chat_expect(arg);
282                if (exit_code>0) break;
283            t=temp2;
284
285                while(*t)
286                {
287                        if (strncmp("CARRIER",t,7)==0)
288                        {/* parse speed information */
289                                i=0;
290                                while(!isdigit(t[i]))
291                                        i++;
292                                t=&t[i];
293                                i=0;
294                                while(isdigit(t[i]))
295                                        i++;
296                                t[i]=0;
297                                sscanf(t,"%d",&speed);
298                                break;                         
299                        }
300                        t++;
301                }
302            if ((arg = getnextcommand(&argv)) != NULL)
303                chat_send(arg);
304                if (exit_code>0) break;
305        }
306
307    if (exit_code) return exit_code;
308    return -speed;
309}
310
311
312
313/*
314 *      Print an error message and terminate.
315 */
316
317void init()
318{
319    set_tty_parameters();
320        speed=0;
321}
322
323void set_tty_parameters()
324{
325    term_parms t;
326
327        if (get_term_param (&t) < 0)
328                syslog(LOG_NOTICE,"Can't get terminal parameters:")
329                ;
330       
331    saved_tty_parameters = t;
332    have_tty_parameters  = 1;
333    t.c_iflag     |= IGNBRK | ISTRIP | IGNPAR;
334    t.c_oflag      = 0;
335    t.c_lflag      = 0;
336    t.c_cc[VERASE] =
337    t.c_cc[VKILL]  = 0;
338    t.c_cc[VMIN]   = 0;
339    t.c_cc[VTIME]  = 1;
340    if (set_term_param (&t) < 0)
341                syslog(LOG_NOTICE,"Can't set terminal parameters:")
342                ;
343}
344
345void break_sequence()
346{
347
348/*    tcsendbreak (0, 0);*/
349}
350
351/*void terminate(status)
352int status;
353{
354    echo_stderr(-1);
355
356    if (have_tty_parameters) {
357        if (set_term_param (&saved_tty_parameters) < 0)
358            fatal(2, "Can't restore terminal parameters: %m");
359    }
360}
361*/
362/*
363 *      'Clean up' this string.
364 */
365char *clean(s, sending)
366register char *s;
367int sending;  /* set to 1 when sending (putting) this string. */
368{
369    char temp[STR_LEN], cur_chr;
370    register char *s1, *phchar;
371    int add_return = sending;
372#define isoctal(chr) (((chr) >= '0') && ((chr) <= '7'))
373
374    s1 = temp;
375    while (*s) {
376        cur_chr = *s++;
377        if (cur_chr == '^') {
378            cur_chr = *s++;
379            if (cur_chr == '\0') {
380                *s1++ = '^';
381                break;
382            }
383            cur_chr &= 0x1F;
384            if (cur_chr != 0) {
385                *s1++ = cur_chr;
386            }
387            continue;
388        }
389
390        if (cur_chr != '\\') {
391            *s1++ = cur_chr;
392            continue;
393        }
394
395        cur_chr = *s++;
396        if (cur_chr == '\0') {
397            if (sending) {
398                *s1++ = '\\';
399                *s1++ = '\\';
400            }
401            break;
402        }
403
404        switch (cur_chr) {
405        case 'b':
406            *s1++ = '\b';
407            break;
408
409        case 'c':
410            if (sending && *s == '\0')
411                add_return = 0;
412            else
413                *s1++ = cur_chr;
414            break;
415
416        case '\\':
417        case 'K':
418        case 'p':
419        case 'd':
420            if (sending)
421                *s1++ = '\\';
422
423            *s1++ = cur_chr;
424            break;
425
426        case 'T':
427            if (sending && phone_num) {
428                for ( phchar = phone_num; *phchar != '\0'; phchar++) 
429                    *s1++ = *phchar;
430            }
431            else {
432                *s1++ = '\\';
433                *s1++ = 'T';
434            }
435            break;
436
437        case 'U':
438            if (sending && phone_num2) {
439                for ( phchar = phone_num2; *phchar != '\0'; phchar++) 
440                    *s1++ = *phchar;
441            }
442            else {
443                *s1++ = '\\';
444                *s1++ = 'U';
445            }
446            break;
447
448        case 'q':
449            quiet = 1;
450            break;
451
452        case 'r':
453            *s1++ = '\r';
454            break;
455
456        case 'n':
457            *s1++ = '\n';
458            break;
459
460        case 's':
461            *s1++ = ' ';
462            break;
463
464        case 't':
465            *s1++ = '\t';
466            break;
467
468        case 'N':
469            if (sending) {
470                *s1++ = '\\';
471                *s1++ = '\0';
472            }
473            else
474                *s1++ = 'N';
475            break;
476           
477        default:
478            if (isoctal (cur_chr)) {
479                cur_chr &= 0x07;
480                if (isoctal (*s)) {
481                    cur_chr <<= 3;
482                    cur_chr |= *s++ - '0';
483                    if (isoctal (*s)) {
484                        cur_chr <<= 3;
485                        cur_chr |= *s++ - '0';
486                    }
487                }
488
489                if (cur_chr != 0 || sending) {
490                    if (sending && (cur_chr == '\\' || cur_chr == 0))
491                        *s1++ = '\\';
492                    *s1++ = cur_chr;
493                }
494                break;
495            }
496
497            if (sending)
498                *s1++ = '\\';
499            *s1++ = cur_chr;
500            break;
501        }
502    }
503
504    if (add_return)
505        *s1++ = '\r';
506
507    *s1++ = '\0'; /* guarantee closure */
508    *s1++ = '\0'; /* terminate the string */
509    return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */
510}
511
512/*
513 * A modified version of 'strtok'. This version skips \ sequences.
514 */
515
516char *expect_strtok (s, term)
517     char *s, *term;
518{
519    static  char *str   = "";
520    int     escape_flag = 0;
521    char   *result;
522
523/*
524 * If a string was specified then do initial processing.
525 */
526    if (s)
527        str = s;
528
529/*
530 * If this is the escape flag then reset it and ignore the character.
531 */
532    if (*str)
533        result = str;
534    else
535        result = (char *) 0;
536
537    while (*str) {
538        if (escape_flag) {
539            escape_flag = 0;
540            ++str;
541            continue;
542        }
543
544        if (*str == '\\') {
545            ++str;
546            escape_flag = 1;
547            continue;
548        }
549
550/*
551 * If this is not in the termination string, continue.
552 */
553        if (strchr (term, *str) == (char *) 0) {
554            ++str;
555            continue;
556        }
557
558/*
559 * This is the terminator. Mark the end of the string and stop.
560 */
561        *str++ = '\0';
562        break;
563    }
564    return (result);
565}
566
567/*
568 * Process the expect string
569 */
570
571void   chat_expect (s)
572char *s;
573{
574    char *expect;
575    char *reply;
576
577    if (strcmp(s, "HANGUP") == 0) {
578        ++hup_next;
579        return ;
580    }
581 
582    if (strcmp(s, "ABORT") == 0) {
583        ++abort_next;
584        return ;
585    }
586
587    if (strcmp(s, "CLR_ABORT") == 0) {
588        ++clear_abort_next;
589        return ;
590    }
591
592    if (strcmp(s, "REPORT") == 0) {
593        ++report_next;
594        return ;
595    }
596
597    if (strcmp(s, "CLR_REPORT") == 0) {
598        ++clear_report_next;
599        return ;
600    }
601
602    if (strcmp(s, "TIMEOUT") == 0) {
603        ++timeout_next;
604        return ;
605    }
606
607    if (strcmp(s, "ECHO") == 0) {
608        ++echo_next;
609        return ;
610    }
611
612    if (strcmp(s, "SAY") == 0) {
613        ++say_next;
614        return ;
615    }
616
617/*
618 * Fetch the expect and reply string.
619 */
620    for (;;) {
621        expect = expect_strtok (s, "-");
622        s      = (char *)0 ;
623
624        if (expect == (char *) 0)
625            return ;
626
627        reply = expect_strtok (s, "-");
628
629/*
630 * Handle the expect string. If successful then exit.
631 */
632        if (get_string (expect))
633            return;
634
635/*
636 * If there is a sub-reply string then send it. Otherwise any condition
637 * is terminal.
638 */
639        if (reply == (char *) 0 || exit_code != 3)
640            break;
641
642        chat_send (reply);
643    }
644
645/*
646 * The expectation did not occur. This is terminal.
647 */
648    return ;
649}
650
651/*
652 *  process the reply string
653 */
654void chat_send (s)
655register char *s;
656{
657    if (say_next) {
658        say_next = 0;
659        s = clean(s,0);
660        write(modem_fd, s, strlen(s));
661        free(s);
662        return;
663    }
664
665    if (hup_next) {
666        hup_next = 0;
667    }
668
669    if (echo_next) {
670        echo_next = 0;
671        echo = (strcmp(s, "ON") == 0);
672        return;
673    }
674
675    if (abort_next) {
676        /* char *s1; */
677       
678       
679           ;
680       
681
682        return;
683    }
684
685
686/*    if (report_next) {
687        char *s1;
688       
689        report_next = 0;
690        if (n_reports >= MAX_REPORTS)
691            {
692              exit_code=2;
693              return;
694            }
695       
696        s1 = clean(s, 0);
697       
698        if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1)
699            {
700              exit_code=1;
701              return;
702            }
703       
704        report_string[n_reports++] = s1;
705       
706        return;
707    }
708*/
709/*    if (clear_report_next) {
710        char *s1;
711        int   i;
712        int   old_max;
713        int   pack = 0;
714       
715        clear_report_next = 0;
716       
717        s1 = clean(s, 0);
718       
719        if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1)
720            {
721              exit_code=1;
722              return;
723            }
724
725        old_max = n_reports;
726        for (i=0; i < n_reports; i++) {
727            if ( strcmp(s1,report_string[i]) == 0 ) {
728                free(report_string[i]);
729                report_string[i] = NULL;
730                pack++;
731                n_reports--;
732            }
733        }
734        free(s1);
735        if (pack)
736            pack_array(report_string,old_max);
737       
738        return;
739    }
740*/
741
742    if (timeout_next) {
743        timeout=atoi(s);
744        timeout_next = 0;
745        chat_timeout = atoi(s);
746       
747        if (chat_timeout <= 0)
748            chat_timeout = DEFAULT_CHAT_TIMEOUT;
749
750
751        return;
752    }
753    if (strcmp(s, "EOT") == 0)
754        s = "^D\\c";
755    else if (strcmp(s, "BREAK") == 0)
756        s = "\\K\\c";
757
758    if (!put_string(s))
759            {
760              exit_code=1;
761              return;
762            }
763}
764
765int get_char()
766{
767    int status;
768    char c;
769    int tries=MAX_TIMEOUTS;
770
771        while(tries)
772        {
773            status = read(modem_fd, &c, 1);
774            switch (status) {
775                   case 1:
776                                return ((int)c & 0x7F);
777                    default:
778                                tries--;                       
779            }
780    }
781        return -1;                                             
782}
783
784int put_char(c)
785int c;
786{
787    int status;
788    char ch = c;
789
790        /* inter-character typing delay (?) */
791
792    status = write(modem_fd, &ch, 1);
793
794    switch (status) {
795    case 1:
796        return (0);
797       
798    default:
799       
800       
801    }
802  return 0;
803}
804
805int write_char (c)
806int c;
807{
808    if (put_char(c) < 0) {
809        return (0);
810    }
811    return (1);
812}
813
814int put_string (s)
815register char *s;
816{
817
818
819    quiet = 0;
820    s = clean(s, 1);
821    while (*s) {
822        register char c = *s++;
823
824        if (c != '\\') {
825            if (!write_char (c))
826                return 0;
827            continue;
828        }
829
830        c = *s++;
831        switch (c) {
832        case 'd':
833            sleep(1);
834            break;
835
836        case 'K':
837            break_sequence();
838            break;
839
840        case 'p':
841            usleep(10000);      /* 1/100th of a second (arg is microseconds) */
842            break;
843
844        default:
845            if (!write_char (c))
846                return 0;
847            break;
848        }
849    }
850
851   /* alarm(0);*/
852    return (1);
853}
854
855/*
856 *      Echo a character to stderr.
857 *      When called with -1, a '\n' character is generated when
858 *      the cursor is not at the beginning of a line.
859 */
860void echo_stderr(n)
861int n;
862{
863/*    static int need_lf;
864    char *s;
865
866    switch (n) {
867    case '\r':           
868        break;
869    case -1:
870        if (need_lf == 0)
871            break;
872 
873    case '\n':
874        write(2, "\n", 1);
875        need_lf = 0;
876        break;
877    default:
878        s = character(n);
879        write(2, s, strlen(s));
880        need_lf = 1;
881        break;
882    }*/
883}
884
885/*
886 *      'Wait for' this string to appear on this file descriptor.
887 */
888
889int get_string(string)
890register char *string;
891{
892    int c, len, minlen;
893    register char *s = temp2, *end = s + STR_LEN;
894    char *logged = temp2;
895    struct termios tios;
896
897    tcgetattr(modem_fd, &tios);
898    tios.c_cc[VMIN] = 0;
899    tios.c_cc[VTIME] = timeout*10/MAX_TIMEOUTS;
900    tcsetattr(modem_fd, TCSANOW, &tios);
901               
902    string = clean(string, 0);
903    len = strlen(string);
904    minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1;
905       
906    if (len > STR_LEN) {
907        exit_code = 1;
908        return 0;
909    }
910
911    if (len == 0) {
912                        return (1);
913    }
914
915
916   while ( (c = get_char()) >= 0) {
917                int n, abort_len;
918
919        *s++ = c;
920        *s=0;
921       
922        if (s - temp2 >= len &&
923            c == string[len - 1] &&
924            strncmp(s - len, string, len) == 0) {
925            return (1);
926        }
927
928        for (n = 0; n < n_aborts; ++n) {
929            if (s - temp2 >= (abort_len = strlen(abort_string[n])) &&
930                strncmp(s - abort_len, abort_string[n], abort_len) == 0) {
931
932                exit_code = n + 4;
933                strcpy(fail_reason = fail_buffer, abort_string[n]);
934                return (0);
935            }
936        }
937
938        if (s >= end) {
939            if (logged < s - minlen) {
940                logged = s;
941            }
942            s -= minlen;
943            memmove(temp2, s, minlen);
944            logged = temp2 + (logged - s);
945            s = temp2 + minlen;
946        }
947    }
948    exit_code = 3;
949    return (0);
950}
951
952/*
953 * Gross kludge to handle Solaris versions >= 2.6 having usleep.
954 */
955
956/*
957  usleep -- support routine for 4.2BSD system call emulations
958  last edit:  29-Oct-1984     D A Gwyn
959  */
960
961
962#if 0
963int
964usleep( usec )                            /* returns 0 if ok, else -1 */
965    long                usec;           /* delay in microseconds */
966{
967  rtems_status_code status;
968  rtems_interval    ticks_per_second;
969  rtems_interval    ticks;
970  status = rtems_clock_get(
971    RTEMS_CLOCK_GET_TICKS_PER_SECOND,
972    &ticks_per_second);
973    ticks = (usec * (ticks_per_second/1000))/1000;
974    status = rtems_task_wake_after( ticks );
975  return 0;
976}
977#endif
978
979void pack_array (array, end)
980    char **array; /* The address of the array of string pointers */
981    int    end;   /* The index of the next free entry before CLR_ */
982{
983    int i, j;
984
985    for (i = 0; i < end; i++) {
986        if (array[i] == NULL) {
987            for (j = i+1; j < end; ++j)
988                if (array[j] != NULL)
989                    array[i++] = array[j];
990            for (; i < end; ++i)
991                array[i] = NULL;
992            break;
993        }
994    }
995}
996
997/*
998 * vfmtmsg - format a message into a buffer.  Like vsprintf except we
999 * also specify the length of the output buffer, and we handle the
1000 * %m (error message) format.
1001 * Doesn't do floating-point formats.
1002 * Returns the number of chars put into buf.
1003 */
1004#define OUTCHAR(c)      (buflen > 0? (--buflen, *buf++ = (c)): 0)
Note: See TracBrowser for help on using the repository browser.