четверг, июня 14, 2012

K&R Язык программирования C. Упражнение 1.19. Напишите функцию reverse(s), которая переписывает свой строковый аргумент в обратном порядке

Занялся на досуге изучением языка си по книжке K&R. Дошёл до задания 1.19. По итогу выполнения решил написать данное сообщение, как памятку себе. Итак, программа выглядит следующим образом:
/* программа, реверсирующая входные строки */
#include <stdio.h>
#define MAXLINE 1000

void reverse(char s[]);
int my_getline(char s[], int);

int main()
{
    int len;
    char line[MAXLINE];

    while((len = my_getline(line, MAXLINE)) > 0) {
        printf("Исходная строка выглядит так: %s", line);
        reverse(line);
        printf("Реверсированная строка выглядит так: %s", line);
    }
    return 0;
}

int my_getline(char s[], int lim)
{
    int i, c;

    for(i = 0; i < lim -1 && (c = getchar()) != EOF && c != '\n'; ++i) {
        s[i] = c;
    }
    if(c == '\n') {
        s[i] = c;
        ++i;
    }
    s[i] = '\0';
    return i;
}

/* функция reverse: переписывает строки в обратном порядке. Суть работы в следующем:
 т.к. мы знаем, что любая строка заканчивается символом '\0', можно на время удалить
 из строки данный символ и занять его место первым элементом массива. После этого можно
 осуществить последовательный перенос всех элементов. В последствии необходимо будет
 "сдвинуть" полученную строку влево */
void reverse(char s[])
{
    int n, i, c, j;

    c = n = 0;
    while(s[n] != '\0') {
        ++n;
    }
    if(s[n-1] == '\n') {
        c = s[n-1]; //c теперь содержит символ перехода на новую строку
        n = n - 2; //не будем подставлять в качестве первого символа переход на новую строку
    }
    /* выясняем, какое у нас число символов в строке: чётное или нечётное */
    if((n%2) == 0) {
        j = n/2;
    } else {
        j = n/2 + 1;
    }
    /* переносим крайние элементы в массиве */
    s[n+1] = s[0];
    s[0] = s[n];
    /* переносим остальные элементы */
    for(i = 0; i < j; ++i) {
        s[i] = s[n-i];
        s[n-i] = s[i+1];
    }
    /* нужно "сдвинуть" символы влево, начиная с середины */
    for(i = j; i < n + 1; ++i) {
        s[i] = s[i+1];
    }
    if(c == '\n') {
        n = n + 1;
        s[n] = '\n';
    }
    s[n+1] = '\0';
}

понедельник, мая 14, 2012

Генерация ложных гудков в трубку после перевода звонка в отвеченное состояние


Настраивал недавно одному клиенту Asterisk. До этого у них стоял тоже астериск, который был настроен каким то "умельцем" - настолько запутанного диалплана я, наверное, не видел ни разу за свою шестилетнюю практику работы. Но пост не об этом. В общем, переводили мы клиента с "их" астериска на "наш" астериск. Вроде бы всё перенесли и система удачно запустилась, но возник один нюанс - у клиента есть 2 GSM-модема, подключенных к FXO-портам шлюзов Linksys SPA3102. И через эти модемы осуществляются звонки на Московские мобильные. На старой системе, при звонке через модемы, в трубку абоненту генерился ложный гудок до тех пор, пока не начинал генерироваться настоящий гудок вызываемой стороной. Ничего сложного, подумал я - поставим опцию r и дело с концом. Но всё оказалось несколько сложнее.Оказывается, при звонке на порт FXO линксис, GSM-модем, подключенный к этому порту сразу же переводил канал в отвеченное состояние и давал в трубку тишину в течение ~20 секунд до тех пор, пока не начинала "гудеть" вызываемая сторона. Скажу честно, с такой проблемой я столкнулся впервые, а клиент говорил, что на старой системе всё работало.
После нескольких дней курения диалпланов предыдущей системы и мануалов в интернете я был в тупике, но, к счастью, интуиция и опыт подсказали ответ - опция G в команде Dial. В описании этой опции говорится:
G(context^exten^pri): If the call is answered, transfer both parties to the specified context and extension. The calling party is transferred to priority x, and the called party to priority x+1. This allows the dialplan to distinguish between the calling and called legs of the call (new in v1.2). You cannot use any options that would affect the post-answer state if this option is used.
что в примерном переводе на русский язык означает следующее:
Если вызов отвечен, он переводится на специальный контекст и указанный экстеншен. Притом, звонящий канал будет переведён на приоритет x, а вызываемый канал на приоритет x+1
В итоге, был составлен "специфичный" контекст следующего содержания:
[custom-test-out-ring]
exten => s,1,Goto(chan_a)
exten => s,n,Goto(chan_b)
exten => s,n(chan_a),Ringing()
exten => s,n,Wait(20)
exten => s,n,Bridge(${DIALEDPEERNAME})
exten => s,n,Hangup()
exten => s,n(chan_b),Wait(50)
exten => s,n,Hangup()
Вызов данного контексте осуществляется следующим образом:

exten => _8XXXXXXXXXX,n,Dial(SIP/linksys/${EXTEN},3,tTG(custom-test-out-ring^s^1))

В итоге, когда осуществляется вызов на указанное направление, при ответе на вызов звонок перекидывается в контекст custom-test-out-ring, в котором звонящий канал переводится на именованный приоритет chan_a, а вызываемый канала - на chan_b. Опытным путём была измерена задержка, которую даёт модем перед тем, как начинает посылать сигналы вызова в трубку и, соответствующее значение было установлено в команду Wait для канала А. Вот таким бесхитростным, вобщем то способом, была решена довольно нетривиальная задача.