浏览代码

Merge pull request #149 from tsoding/remove-pcre2-dep

Remove pcre2 dep
Alexey Kutepov 4 年之前
父节点
当前提交
3924eac36c
共有 10 个文件被更改,包括 204 次插入122 次删除
  1. 3 3
      .github/workflows/ci.yml
  2. 2 2
      Makefile
  3. 1 1
      README.md
  4. 132 14
      src/aids.hpp
  5. 5 5
      src/diffimg.cpp
  6. 0 3
      src/vodus.cpp
  7. 3 3
      src/vodus_main.cpp
  8. 56 83
      src/vodus_message.cpp
  9. 2 7
      src/vodus_video_params.cpp
  10. 0 1
      src/vodus_video_params.hpp

+ 3 - 3
.github/workflows/ci.yml

@@ -9,7 +9,7 @@ jobs:
       - name: install dependencies
         run: |
           sudo apt-get update
-          sudo apt-get install -qq nasm libfreetype6-dev libcurl4-openssl-dev libpcre2-dev libglfw3-dev
+          sudo apt-get install -qq nasm libfreetype6-dev libcurl4-openssl-dev libglfw3-dev
       - uses: actions/cache@v2
         with:
           # TODO(#84): centralize third party versions in the build
@@ -48,7 +48,7 @@ jobs:
       - uses: actions/checkout@v1
       - name: install dependencies
         run: |
-          brew install nasm freetype2 openssl pcre2 glfw
+          brew install nasm freetype2 openssl glfw
       - uses: actions/cache@v2
         with:
           path: |
@@ -88,7 +88,7 @@ jobs:
       - name: install dependencies
         run: |
           sudo apt-get update
-          sudo apt-get install -qq nasm libfreetype6-dev libcurl4-openssl-dev libpcre2-dev libglfw3-dev
+          sudo apt-get install -qq nasm libfreetype6-dev libcurl4-openssl-dev libglfw3-dev
       - uses: actions/cache@v2
         with:
           path: |

+ 2 - 2
Makefile

@@ -8,9 +8,9 @@ endif
 
 # TODO(#87): we need an option to build with system libraries
 ifeq ($(UNAME), Darwin)
-VODUS_PKGS=freetype2 libpcre2-8 glfw3
+VODUS_PKGS=freetype2 glfw3
 else
-VODUS_PKGS=freetype2 libpcre2-8 glfw3 gl
+VODUS_PKGS=freetype2 glfw3 gl
 endif
 VODUS_CXXFLAGS=-Wall -fno-exceptions -std=c++17 $(VODUS_EXTRA_CXXFLAGS) -ggdb `pkg-config --cflags $(VODUS_PKGS)` -I./third_party/ffmpeg-4.3-dist/usr/local/include/ -I./third_party/giflib-5.2.1-dist/usr/local/include/
 VODUS_LIBS=`pkg-config --libs $(VODUS_PKGS)` -L./third_party/giflib-5.2.1-dist/usr/local/lib/ ./third_party/giflib-5.2.1-dist/usr/local/lib/libgif.a -L./third_party/ffmpeg-4.3-dist/usr/local/lib/ -L./third_party/glfw-3.3.2-dist/usr/local/lib/ -lavcodec -lavutil -lswresample -pthread -lm -llzma -lz -ldl

+ 1 - 1
README.md

@@ -15,7 +15,7 @@ changed at any moment or stop working at all.**
 #### Debian
 
 ```console
-$ sudo apt-get install nasm libfreetype6-dev libcurl4-openssl-dev libpcre2-dev
+$ sudo apt-get install nasm libfreetype6-dev libcurl4-openssl-dev
 ```
 
 #### NixOS

+ 132 - 14
src/aids.hpp

@@ -21,7 +21,7 @@
 //
 // ============================================================
 //
-// aids — 0.15.0 — std replacement for C++. Designed to aid developers
+// aids — 0.22.0 — std replacement for C++. Designed to aid developers
 // to a better programming experience.
 //
 // https://github.com/rexim/aids
@@ -30,6 +30,16 @@
 //
 // ChangeLog (https://semver.org/ is implied)
 //
+//   0.22.0 panic()
+//   0.21.0 void sprint1(String_Buffer *buffer, unsigned int x)
+//   0.20.0 Escape
+//   0.19.0 unwrap_or_panic()
+//   0.18.0 Rename Args::pop() -> Args::shift()
+//          Add more details to Stretchy_Buffer deprecation message
+//   0.17.0 Dynamic_Array::concat()
+//          Dynamic_Array::expand_capacity()
+//   0.16.0 Dynamic_Array
+//          deprecate Stretchy_Buffer
 //   0.15.0 Make min() and max() variadic
 //   0.14.0 size_t String_View::count_chars(char x) const
 //   0.13.3 Fix control flow in utf8_get_code
@@ -431,34 +441,88 @@ namespace aids
     }
 
     ////////////////////////////////////////////////////////////
-    // STRETCHY BUFFER
+    // DYNAMIC ARRAY
     ////////////////////////////////////////////////////////////
 
-    struct Stretchy_Buffer
+    template <typename T>
+    struct Dynamic_Array
     {
         size_t capacity;
         size_t size;
-        char *data;
+        T *data;
+
+        void expand_capacity()
+        {
+            capacity = data ? 2 * capacity : 256;
+            data = (T*)realloc((void*)data, capacity * sizeof(T));
+        }
+
+        void push(T item)
+        {
+            while (size + 1 > capacity) {
+                expand_capacity();
+            }
+
+            memcpy(data + size, &item, sizeof(T));
+            size += 1;
+        }
 
-        void push(const char *that_data, size_t that_size)
+        void concat(const T *items, size_t items_count)
         {
-            if (size + that_size > capacity) {
-                capacity = 2 * capacity + that_size;
-                data = (char*)realloc((void*)data, capacity);
+            while (size + 1 > capacity) {
+                expand_capacity();
             }
 
-            memcpy(data + size, that_data, that_size);
-            size += that_size;
+            memcpy(data + size, items, sizeof(T) * items_count);
+            size += items_count;
         }
 
-        template <typename T>
-        void push(T x)
+        bool contains(T item)
         {
-            push((char*) &x, sizeof(x));
+            for (size_t i = 0; i < size; ++i) {
+                if (item == data[i]) {
+                    return true;
+                }
+            }
+
+            return false;
         }
     };
 
-    void print1(FILE *stream, Stretchy_Buffer buffer)
+    ////////////////////////////////////////////////////////////
+    // STRETCHY BUFFER
+    ////////////////////////////////////////////////////////////
+
+    namespace deprecated {
+        struct Stretchy_Buffer
+        {
+            size_t capacity;
+            size_t size;
+            char *data;
+
+            void push(const char *that_data, size_t that_size)
+            {
+                if (size + that_size > capacity) {
+                    capacity = 2 * capacity + that_size;
+                    data = (char*)realloc((void*)data, capacity);
+                }
+
+                memcpy(data + size, that_data, that_size);
+                size += that_size;
+            }
+
+            template <typename T>
+            void push(T x)
+            {
+                push((char*) &x, sizeof(x));
+            }
+        };
+    }
+
+    using Stretchy_Buffer [[deprecated("Use Dynamic_Array instead. Stretchy_Buffer is limited to only `char`-s while Dynamic_Array<T> can work with any type T.")]] = deprecated::Stretchy_Buffer;
+
+    [[deprecated("Use Dynamic_Array instead. Stretchy_Buffer is limited to only `char`-s while Dynamic_Array<T> can work with any type T.")]]
+    void print1(FILE *stream, deprecated::Stretchy_Buffer buffer)
     {
         fwrite(buffer.data, 1, buffer.size, stream);
     }
@@ -472,7 +536,13 @@ namespace aids
         int argc;
         char **argv;
 
+        [[deprecated("Use Args::shift() instead. It was decided to rename `pop` to `shift` since it creates confusion with the pop operation of stacks which removes the elements from the other end. And shift is common operation in Bash and Perl (probably others) for parsing command line arguments.")]]
         char *pop()
+        {
+            return shift();
+        }
+
+        char *shift()
         {
             char *result = *argv;
             argv += 1;
@@ -547,6 +617,15 @@ namespace aids
         buffer->size = min(buffer->size + n, buffer->capacity - 1);
     }
 
+    void sprint1(String_Buffer *buffer, unsigned int x)
+    {
+        int n = snprintf(
+            buffer->data + buffer->size,
+            buffer->capacity - buffer->size,
+            "%u", x);
+        buffer->size = min(buffer->size + n, buffer->capacity - 1);
+    }
+
     void sprint1(String_Buffer *buffer, long unsigned int x)
     {
         int n = snprintf(
@@ -632,6 +711,11 @@ namespace aids
         sprint1(buffer, another_buffer.view());
     }
 
+    struct Escape
+    {
+        String_View unwrap;
+    };
+
     ////////////////////////////////////////////////////////////
     // PRINT
     ////////////////////////////////////////////////////////////
@@ -709,6 +793,40 @@ namespace aids
         print1(stream, '\n');
     }
 
+
+    template <typename... Args>
+    void panic(Args... args)
+    {
+        println(stderr, args...);
+        exit(1);
+    }
+
+    template <typename T, typename... Args>
+    T unwrap_or_panic(Maybe<T> maybe, Args... args)
+    {
+        if (!maybe.has_value) {
+            panic(args...);
+        }
+
+        return maybe.unwrap;
+    }
+
+    void print1(FILE *stream, Escape escape)
+    {
+        for (size_t i = 0; i < escape.unwrap.count; ++i) {
+            switch (escape.unwrap.data[i]) {
+            case '\a': print(stream, "\\a"); break;
+            case '\b': print(stream, "\\b"); break;
+            case '\f': print(stream, "\\f"); break;
+            case '\n': print(stream, "\\n"); break;
+            case '\r': print(stream, "\\r"); break;
+            case '\t': print(stream, "\\t"); break;
+            case '\v': print(stream, "\\v"); break;
+            default: print(stream, escape.unwrap.data[i]);
+            }
+        }
+    }
+
     void print1(FILE *stream, Pad pad)
     {
         for (size_t i = 0; i < pad.n; ++i) {

+ 5 - 5
src/diffimg.cpp

@@ -18,23 +18,23 @@ int main(int argc, char *argv[])
     const char *actual_filepath = NULL;
     float threshold = 10.0f;
 
-    args.pop();
+    args.shift();
     while (!args.empty()) {
-        auto flag = cstr_as_string_view(args.pop());
+        auto flag = cstr_as_string_view(args.shift());
         if (flag == "-e"_sv) {
             if (args.empty()) {
                 println(stderr, "No argument for flag `", flag, "`");
                 usage(stderr);
                 exit(1);
             }
-            expected_filepath = args.pop();
+            expected_filepath = args.shift();
         } else if (flag == "-a"_sv) {
             if (args.empty()) {
                 println(stderr, "No argument for flag `", flag, "`");
                 usage(stderr);
                 exit(1);
             }
-            actual_filepath = args.pop();
+            actual_filepath = args.shift();
         } else if (flag == "-t"_sv) {
             if (args.empty()) {
                 println(stderr, "No argument for flag `", flag, "`");
@@ -42,7 +42,7 @@ int main(int argc, char *argv[])
                 exit(1);
             }
 
-            const auto threshold_sv = cstr_as_string_view(args.pop());
+            const auto threshold_sv = cstr_as_string_view(args.shift());
             const auto maybe_threshold = threshold_sv.as_float();
             if (!maybe_threshold.has_value) {
                 println(stderr, threshold_sv, " is not a float");

+ 0 - 3
src/vodus.cpp

@@ -7,9 +7,6 @@
 
 #include <algorithm>
 
-#define PCRE2_CODE_UNIT_WIDTH 8
-#include <pcre2.h>
-
 #include <ft2build.h>
 #include FT_FREETYPE_H
 #include <gif_lib.h>

+ 3 - 3
src/vodus_main.cpp

@@ -67,21 +67,21 @@ void sample_chat_log_animation(Message *messages,
 int main(int argc, char *argv[])
 {
     Args args = {argc, argv};
-    args.pop();                 // skip program name;
+    args.shift();                 // skip program name;
 
     if (args.empty()) {
         println(stderr, "[ERROR] Input filename is not provided");
         usage(stderr);
         abort();
     }
-    const char *input_filepath = args.pop();
+    const char *input_filepath = args.shift();
 
     if (args.empty()) {
         println(stderr, "[ERROR] Output filename is not provided");
         usage(stderr);
         abort();
     }
-    const char *output_filepath = args.pop();
+    const char *output_filepath = args.shift();
 
     Video_Params params = default_video_params();
     patch_video_params_from_args(&params, &args);

+ 56 - 83
src/vodus_message.cpp

@@ -1,6 +1,8 @@
+using Timestamp = uint64_t;
+
 struct Message
 {
-    uint64_t timestamp;
+    Timestamp timestamp;
     String_View nickname;
     String_View message;
 
@@ -167,69 +169,60 @@ struct Message_Buffer
     }
 };
 
-String_View get_substring_view_by_name(pcre2_code *re,
-                                       pcre2_match_data *match_data,
-                                       const char *name,
-                                       String_View subject)
+Timestamp chop_timestamp(String_View *input)
 {
-    PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(match_data);
-    int index = pcre2_substring_number_from_name(re, (PCRE2_SPTR) name);
-    const char* substring_start = subject.data + ovector[2*index];
-    size_t substring_length = ovector[2*index+1] - ovector[2*index];
-    return {substring_length, substring_start};
-}
-
-uint64_t get_timestamp_from_match_data(pcre2_code *re,
-                                       pcre2_match_data *match_data,
-                                       String_View subject)
-{
-    String_View hours = get_substring_view_by_name(re, match_data, "hours", subject);
-    String_View minutes = get_substring_view_by_name(re, match_data, "minutes", subject);
-    String_View seconds = get_substring_view_by_name(re, match_data, "seconds", subject);
-    String_View mseconds = get_substring_view_by_name(re, match_data, "milliseconds", subject);
-
-    uint64_t mseconds_value = 0;
-    for (size_t i = 0; i < 3; ++i) {
-        uint64_t x = 0;
-        if (mseconds.count > 0) {
-            x = *mseconds.data - '0';
-            mseconds.chop(1);
+    input->chop_by_delim('[');
+    auto raw_timestamp = input->chop_by_delim(']').trim();
+
+    // TODO: message parsing should give more precise position of the syntax errors
+    auto hours = unwrap_or_panic(
+        raw_timestamp.chop_by_delim(':').trim().as_integer<uint64_t>(),
+        "Incorrect timestamp. Hours must be a number.");
+
+    auto minutes = unwrap_or_panic(
+        raw_timestamp.chop_by_delim(':').trim().as_integer<uint64_t>(),
+        "Incorrect timestamp. Minutes must be a number.");
+
+    auto seconds = unwrap_or_panic(
+        raw_timestamp.chop_by_delim('.').trim().as_integer<uint64_t>(),
+        "Incorrect timestamp. Seconds must be a number");
+
+    auto mseconds = 0;
+
+    if (raw_timestamp.count > 0) {
+        for (size_t i = 0; i < 3; ++i) {
+            if (i < raw_timestamp.count) {
+                if (isdigit(raw_timestamp.data[i])) {
+                    mseconds = mseconds * 10 + raw_timestamp.data[i] - '0';
+                } else {
+                    panic("Incorrect timestamp. Milliseconds must be a number");
+                }
+            } else {
+                mseconds *= 10;
+            }
         }
-        mseconds_value = mseconds_value * 10 + x;
     }
 
-    const uint64_t timestamp =
-        (hours.as_integer<uint64_t>().unwrap * 60 * 60 +
-         minutes.as_integer<uint64_t>().unwrap * 60 +
-         seconds.as_integer<uint64_t>().unwrap) * 1000 +
-        mseconds_value;
-
-    return timestamp;
+    return (hours * 60 * 60 + minutes * 60 + seconds) * 1000 + mseconds;
 }
 
-size_t parse_messages_from_string_view(String_View input, Message **messages, Video_Params params, const char *input_filepath)
+String_View chop_nickname(String_View *input)
 {
-    int errorcode = 0;
-    PCRE2_SIZE erroroffset = 0;
-    pcre2_code *re = pcre2_compile(
-        (PCRE2_SPTR) params.message_regex.data,
-        params.message_regex.count, 0,
-        &errorcode,
-        &erroroffset,
-        NULL);
-
-    if (re == NULL) {
-        PCRE2_UCHAR buffer[256];
-        pcre2_get_error_message(errorcode, buffer, sizeof(buffer));
-        // TODO(#136): better PCRE2 compilation errors
-        printf("PCRE2 compilation of message_regex failed at offset %d: %s\n", (int)erroroffset, buffer);
-        exit(1);
-    }
-    defer(pcre2_code_free(re));
+    input->chop_by_delim('<');
+    auto nickname = input->chop_by_delim('>');
+    return nickname;
+}
 
-    pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(re, NULL);
-    defer(pcre2_match_data_free(match_data));
+String_View chop_message(String_View *input)
+{
+    return input->trim();
+}
 
+size_t parse_messages_from_string_view(String_View input,
+                                       Message **messages,
+                                       Video_Params params,
+                                       const char *input_filepath)
+{
     size_t expected_messages_size = input.count_chars('\n') + 1;
     if (params.messages_limit.has_value) {
         expected_messages_size = min(expected_messages_size, params.messages_limit.unwrap);
@@ -238,36 +231,15 @@ size_t parse_messages_from_string_view(String_View input, Message **messages, Vi
     *messages = new Message[expected_messages_size];
 
     size_t messages_size = 0;
-    for (size_t line_number = 1; input.count > 0 && messages_size < expected_messages_size; ++line_number) {
+    for (size_t line_number = 1;
+         input.count > 0 && messages_size < expected_messages_size;
+         ++line_number)
+    {
         String_View message = input.chop_by_delim('\n');
 
-        int rc = pcre2_match(
-            re,                           /* the compiled pattern */
-            (PCRE2_SPTR) message.data,    /* the subject string */
-            message.count,                /* the length of the subject */
-            0,                            /* start at offset 0 in the subject */
-            0,                            /* default options */
-            match_data,                   /* block for storing the result */
-            NULL);                        /* use default match context */
-
-        if (rc < 0) {
-            print(stderr, input_filepath, ":", line_number, ": ");
-
-            switch(rc) {
-            case PCRE2_ERROR_NOMATCH:
-                println(stderr, "message_regex did not match this line");
-                break;
-            default:
-                println(stderr, "Matching error ", rc);
-                break;
-            }
-
-            exit(1);
-        }
-
-        (*messages)[messages_size].timestamp = get_timestamp_from_match_data(re, match_data, message);
-        (*messages)[messages_size].nickname = get_substring_view_by_name(re, match_data, "nickname", message);
-        (*messages)[messages_size].message = get_substring_view_by_name(re, match_data, "message", message).trim();
+        (*messages)[messages_size].timestamp = chop_timestamp(&message);
+        (*messages)[messages_size].nickname  = chop_nickname(&message);
+        (*messages)[messages_size].message   = chop_message(&message);
         messages_size++;
     }
 
@@ -275,5 +247,6 @@ size_t parse_messages_from_string_view(String_View input, Message **messages, Vi
               [](const Message &m1, const Message &m2) {
                   return m1.timestamp < m2.timestamp;
               });
+
     return messages_size;
 }

+ 2 - 7
src/vodus_video_params.cpp

@@ -38,7 +38,6 @@ void print1(FILE *stream, Video_Params params)
     println(stream, "    .bitrate = ", params.bitrate);
     println(stream, "    .font = ", params.font);
     println(stream, "    .message_limit = ", params.messages_limit);
-    println(stream, "    .message_regex = ", params.message_regex);
     print(stream, "}");
 }
 
@@ -55,8 +54,6 @@ Video_Params default_video_params() {
     params.bitrate           = 400'000;
     params.font              = ""_sv;
     params.messages_limit    = {};
-
-    params.message_regex     = "\\[(?<hours>\\d+):(?<minutes>\\d+):(?<seconds>\\d+)(\\.(?<milliseconds>\\d+))?\\] \\<(?<nickname>.+?)\\> (?<message>.*)"_sv;
     return params;
 }
 
@@ -174,8 +171,6 @@ void patch_video_params_from_flag(Video_Params *params, String_View flag, String
         params->font = value;
     } else if (flag == "messages_limit"_sv || flag == "messages-limit"_sv) {
         params->messages_limit = {true, parse_integer_flag<size_t>(flag, value)};
-    } else if (flag == "message_regex"_sv || flag == "message-regex"_sv) {
-        params->message_regex = value;
     } else if (flag == "output_type"_sv || flag == "output-type"_sv) {
         if (value == "video"_sv) {
             params->output_type = Output_Type::Video;
@@ -211,7 +206,7 @@ void patch_video_params_from_flag(Video_Params *params, String_View flag, String
 void patch_video_params_from_args(Video_Params *params, Args *args)
 {
     while (!args->empty()) {
-        auto flag = cstr_as_string_view(args->pop());
+        auto flag = cstr_as_string_view(args->shift());
         flag.chop(2);
 
         if (args->empty()) {
@@ -219,7 +214,7 @@ void patch_video_params_from_args(Video_Params *params, Args *args)
             usage(stderr);
             abort();
         }
-        auto value = cstr_as_string_view(args->pop());
+        auto value = cstr_as_string_view(args->shift());
 
         if (flag == "config"_sv) {
             patch_video_params_from_file(params, value);

+ 0 - 1
src/vodus_video_params.hpp

@@ -21,7 +21,6 @@ struct Video_Params
     int bitrate;
     String_View font;
     Maybe<size_t> messages_limit;
-    String_View message_regex;
 };
 
 String_View param_names[] = {