1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <algorithm>
6#include <iostream>
7#include <string>
8#include <vector>
9
10#include "base/basictypes.h"
11
12// Include once to get the type definitions
13#include "chrome/common/all_messages.h"
14#include "content/common/all_messages.h"
15
16struct msginfo {
17  const char* name;
18  int id;
19  int in_count;
20  int out_count;
21
22  bool operator< (const msginfo& other) const {
23    return id < other.id;
24  }
25};
26
27// Redefine macros to generate table
28#include "ipc/ipc_message_null_macros.h"
29#undef IPC_MESSAGE_DECL
30#define IPC_MESSAGE_DECL(kind, type, name, in, out, ilist, olist) \
31  { #name, IPC_MESSAGE_ID(), in, out },
32
33static msginfo msgtable[] = {
34#include "chrome/common/all_messages.h"
35#include "content/common/all_messages.h"
36};
37#define MSGTABLE_SIZE (sizeof(msgtable)/sizeof(msgtable[0]))
38COMPILE_ASSERT(MSGTABLE_SIZE, CHECK_YOUR_HEADERS_FOR_AN_EXTRA_SEMICOLON);
39
40static bool check_msgtable() {
41  bool result = true;
42  int previous_class_id = 0;
43  int highest_class_id = 0;
44  std::vector<int> exemptions;
45
46  // Exclude test and other non-browser files from consideration.  Do not
47  // include message files used inside the actual chrome browser in this list.
48  exemptions.push_back(TestMsgStart);
49  exemptions.push_back(FirefoxImporterUnittestMsgStart);
50  exemptions.push_back(ShellMsgStart);
51
52  for (size_t i = 0; i < MSGTABLE_SIZE; ++i) {
53    int class_id = IPC_MESSAGE_ID_CLASS(msgtable[i].id);
54    if (class_id >= LastIPCMsgStart) {
55      std::cout << "Invalid LastIPCMsgStart setting\n";
56      result = false;
57    }
58    while (class_id > previous_class_id + 1) {
59      std::vector<int>::iterator iter;
60      iter = find(exemptions.begin(), exemptions.end(), previous_class_id+1);
61      if (iter == exemptions.end()) {
62        std::cout << "Missing message file: gap before " << class_id << "\n";
63        result = false;
64        break;
65      }
66      ++previous_class_id;
67    }
68    previous_class_id = class_id;
69    if (class_id > highest_class_id)
70      highest_class_id = class_id;
71  }
72
73  while (LastIPCMsgStart > highest_class_id + 1) {
74    std::vector<int>::iterator iter;
75    iter = find(exemptions.begin(), exemptions.end(), highest_class_id+1);
76    if (iter == exemptions.end()) {
77      std::cout << "Missing message file: gap before LastIPCMsgStart\n";
78      result = false;
79      break;
80    }
81    ++highest_class_id;
82  }
83
84  if (!result)
85    std::cout << "Please check {chrome,content}/common/all_messages.h.\n";
86
87  return result;
88}
89
90static void dump_msgtable(bool show_args, bool show_ids,
91                          bool show_comma, const char *prefix) {
92  bool first = true;
93  for (size_t i = 0; i < MSGTABLE_SIZE; ++i) {
94    if ((!prefix) || strstr(msgtable[i].name, prefix) == msgtable[i].name) {
95      if (show_comma) {
96        if (!first)
97          std::cout << ",";
98        first = false;
99        std::cout << msgtable[i].id;
100      } else {
101        if (show_ids)
102          std::cout << msgtable[i].id << " " <<
103              IPC_MESSAGE_ID_CLASS(msgtable[i].id) << "," <<
104              IPC_MESSAGE_ID_LINE(msgtable[i].id) << " ";
105        std::cout << msgtable[i].name;
106        if (show_args) {
107          std::cout << "(" << msgtable[i].in_count << " IN, "  <<
108              msgtable[i].out_count << " OUT)";
109        }
110        std::cout << "\n";
111      }
112    }
113  }
114  if (show_comma)
115    std::cout << "\n";
116}
117
118int main(int argc, char **argv) {
119  bool show_args = false;
120  bool show_ids  = false;
121  bool skip_check = false;
122  bool show_comma = false;
123  const char *filter = NULL;
124
125  while (--argc > 0) {
126    ++argv;
127    if (std::string("--args") == *argv) {
128      show_args = true;
129    } else if (std::string("--comma") == *argv) {
130      show_comma = true;
131    } else if (std::string("--filter") == *argv) {
132      filter = *(++argv);
133      --argc;
134    } else if (std::string("--ids") == *argv) {
135      show_ids = true;
136    } else if (std::string("--no-check") == *argv) {
137      skip_check = true;
138    } else {
139      std::cout <<
140          "usage: ipclist [--args] [--ids] [--no-check] [--filter prefix] "
141          "[--comma]\n";
142      return 1;
143    }
144  }
145
146  std::sort(msgtable, msgtable + MSGTABLE_SIZE);
147
148  if (!skip_check && check_msgtable() == false)
149    return 1;
150
151  dump_msgtable(show_args, show_ids, show_comma, filter);
152  return 0;
153}
154
155